 Well, should we do an episode and then we can maybe try and do some of a bulls*** at the end for Lucas to cut around? No, Link. Alright, am I? What? What? So we spent the last couple of episodes talking about real things. Real talk. Let's stop that. Let's not do that. So yeah, I thought why not just talk about some imaginary stuff this time. I want to talk about import maps, which is a new proposal that is very much of the early messing around. Right, so let's give it context because I've seen, we have an article on this. We have had a lot of confusion about how stable certain features are when we announce them. Where is it at? Well, yes. Before we talk about what it is, I would say some of it is in Chrome Canary behind the flag, an origin trial. So you can experiment with it on production with the whole origin trial thing. But none of this is set in stone, so it could still change how it works, why it works. This episode could be completely useless by the time it goes out. So I guess it's also pretty much Chrome only then at this point. Like not the other browsers have it behind the flag? Nope. It'd be Chrome only. So what is it? What is it? Actually, I'm going to answer that because I did the slides and the script and everything. We've got a module import with your old module scripts. See, I used your library. See, you happy? Did you use IDB key valve at once? No, no. I've changed it up this time. But a lot of us are more familiar to seeing something like this. Yeah, because that's how the node import works and most of the bundless support, that kind of specifier where you just say, just put the node package name in there and we'll resolve the rest. And the way this actually works in Node is it will start at whatever module contains this and it will go up through all of the directories, all the parent directories, looking for directors that have node modules alongside. All right, so it goes upwards and tries to find the most, the closest node module? No, it'll find them all. Oh, really? Yeah. I think it's wasteful. It goes and find them all and then it will find two. So you put a node modules folder in Slash, like in the root of my hard drive. I think that will work. That's amazing. But then there's also the special global one for your global modules, so that goes at the end as well. Can you do it in your existing? Well, yeah, if you do npm install dash g, dash g, it goes into your global stuff. Oh, right. I never thought about that. Yeah. And then it will iterate through all of those and it will look for a directory called comlink in each of those. And if there's multiple? Well, it will. So it's going through them close? Yes. So when it finds comlink in one of them, it will go, right, does this have a package, Jason? If it does, then I'm going to look in the main thing. And that's the script I'm going to load. If it doesn't have that, then I'm going to try and load index.js. If that's not there, I'm going to try and load index.json. If that's not there, I'm going to try and load index.node for binary modules. Yes, that's how it works. And if they're not there, it then goes up the directories. Yeah. And off it goes. We want that on the web. Is that what you're saying? That's the problem is we literally cannot do that on the web because imagine how many requests it would have to make just to find a script, right? Time to interactive. Two and a half years. Yeah. Exactly. So we needed a new system in order to bring this to the web and that is import maps. That is what we're going to talk about. Oh, it's a new type. It's a new script type. Can I also put in a file? Yes. Yes, you can. And you shouldn't. And we will get on to why. But this is what it looks like. So it's literally a map that maps from the identifier stuff. Oh, that's interesting because I remember that there is a rule for both dynamic and static imports. They have to start with slash or with a relative or absolute path. Yes. They were not allowed to start with like this. Yes. Modules on the web right now have to start with a dot. I think it has to be like dot, dot, dot. Or a valid URL or slash. Right. Something like that. OK. And so this would let you with this. Now you would just be able to reference. Oh, cool. OK. So there is no way that an import map identifier could clash with existing production code out there right now because of that rule. Hold on. Hold on to that. As long as you've got this, one of these has to go before anything that imports anything, any import statement. If you have one of these later on, it will just error. You'll get an error on this script tag and it will just be ignored. OK. So ideally right in the head of your document for everything else. That's why you probably shouldn't put them in a file. That's why you probably shouldn't put them in a file. But yes, now this works. Neat. Just works. Thank you for spoiling my next slide multiple times. It's just to show we don't rehearse this, right? Yes, I would say you can do this. It has to have a special mine type. But yes, you shouldn't because then you've got this head of line blocking thing. So will that mean that a script type import map is also deferred by default? Because modules are deferred by default. No, this will, I mean, it's not going to block rendering of anything, but it will be immediate fetch. And it will block subsequent script tags. Script tags. So basically, if you put in an excellent file but put the script tag high up, you should still be fine. But it won't lie on it, but you should be fine. But there's a reason we in line scripts, right? Because if it's a very small file, then the amount you pay for that request and response. Will people really keep small import maps? I kind of expect them to be like... That is a question. And yeah, and it would be interesting. So maybe with some of the use cases we go through here, I have been also wondering how large these might get. Because the thing we saw there is I would say one of the more boring use cases for it. Another interesting one. So this is what the example we had before. I can import comlink because it's in the import map. But we've seen something like this. That's the thing that usually works in Node. In NodeLand. You would have, yep. This works as well. Really? You do something like this. So there's a special rule. If the thing ends in a slash, then you are defining a prefix for all of those. That's really nice that they thought of that. I would have expected to have to define... Every single one. Analyze all the imports I have and define a map. This is actually really neat. But they don't have a rule that can just define the last one. An index is assumed. It is a node. No. Index is not assumed. And also things like... In Node, you can miss out the extension. Oh yeah, don't know. I mean that wouldn't just... You could use import maps to work around that, but you would have to do every single file. Right. You had to define everything. It's like, yes, the thing without the extension it maps to the thing with the extension. Yes, so you can do that, but probably don't unless you just, for some reason, know of a way around it. You can do this. Also maybe I can do like rewrites. So something that is already a valid import path. I can now just say, you know what? It's actually here. Yes, absolutely. Oh, that's nice. And it's... You could say that this could just create a lot of confusing code where your scripts are doing... But I think there's a really interesting use case with this that I'm really excited about. So here's an example in port, but in production it will most likely look more like this. Yes, because you... At least it should be because good caching, you need this. You need your unique file name. So then if you change the file, you will watch this. There you go. Change the hash. I set you up for this one. I know. That's great. And then it means you've changed the file, so each of those resources can cache forever because you changed the file when you're changing the content. But the problem with this is you've now also changed the content of the parent file. Yes. So you need to update the hash of that file. If nothing else changed, people will download the file that is exactly the same, except for the imports. Yes. And now with the import map, I see where you're going with this. Yes. So even with a small module change, you end up invalidating like massive tree... Potentially like... The whole lot. Always from where you did the change to the root of your thing, at least that one branch, potentially more. It will all invalidate. So the idea is what if we could just do that and then in your import map, that's where the hash goes. Very nice. So that means if you change foo, we just change foo, watch. And so the interesting thing is that this wouldn't be possible with HTTP redirects or rewrites because it wouldn't hit the HTTP cache. Exactly. You could do it maybe in a service worker, I guess. You could do this in a service worker. You could intercept all of this stuff, but it wouldn't be there for that very first request where your service worker isn't installed. Whereas with imports, import maps, it is just there. That's a really exciting use case, actually, for this. I think it's great. And so that means, yes, the user will obviously have to download the new foo, blah, blah, blah, blah. But only that? Only that. Only that small change. The entire rest of the pipeline can still just rely on, you know, hash to load all the static imports before executing so everything will just work and keep working. So I think that's, yeah, I think that's a lovely little use case. So, here's a fun one. So, here's a fun one. We haven't done that in a while. Although I said these script things, these import map scripts, they have to be before anything that imports anything, otherwise they're invalid. So they have to be the... Oh, they're actually invalid. I didn't catch that. I thought the modules above it wouldn't respect them. No, it will error and ignore. That's probably a good idea. Yeah, so it won't error modules. It will just error on the script elements. You'll see an error that this is not in the correct place, but it will also let the other thing that have invalid import statements error out. Yeah. Okay. But you can still create them dynamically, as long as you're still creating them dynamically before any other imports. And I think this is really cool because you could have something like this where it does a feature test. Like, oh, it could be like a new JavaScript thing, could be a new DOM thing. Oh, that is really cool. New JavaScript syntax, and you could say, right, now dump out one of these import maps instead of loading main. So for example, I could say, do you have readable stream, transform stream, writeable stream? If I do, I'm just going to create this redirect to a small file, we'll just re-export the native. If not, load the entire polyfill thing. And in my code, I just import one normal module. I will get the polyfill if it needs to be one. Otherwise, it won't be. Exactly that. That's really cool. But it means you could do the same with new JavaScript syntax. So if the scope operator became a thing, let's hope it does. It's not going to, though, is it? But let's hope it does. It means you could do something like this, like direct it to another file, which makes use of that and therefore doesn't have to be transpiled, that kind of thing. Could be smaller. Could be smaller, hopefully. So why did you do this? Do you know why I did this? No, that's why I'm asking. What? Come on, we do the show. Why do you do this? Oh, do you? Sometimes we make the leave on this show a little bit, No, I legit, I guess it has to with some sort of escaping, but I didn't. It is. Because it's just a normal string. It's like the only part we make use of the template literal. Yeah, the HTML parser, once it enters a script, the end of your script is when there is angle bracket slash script, angle bracket. That's the end of your script. So without this little trick, the script would end there and all of this would bleed into the HTML. Oh, that's the thing. Yes, yes. I remember now that even in a string literal, you can't just have angle bracket slash script because by the time your file gets parsed, the parser would be like, yeah, script ncm. Yeah, because this is HTML parser time rather than JavaScript parser time. So, yeah, you've always got to do something to work around. This is the first time, I think, I've ever seen this. Like both this kind of escape, but also insert, adjacent HTML. I've never used it. I actually love insert adjacent HTML. I always create, to create element and set inner HTML or something. Yeah, and I quite often end up doing that or you're using some sort of library that's essentially making it easier for you, but for the sake of a slide, and this is an old Microsoft API. This was one of the non-standard things that went into Internet Explorer, blah, blah, blah. Four. It could be, it could be 5.5 or so. In that era somewhere, but they standardized it because it is actually pretty useful, very weird API. You can say, I want it to go after the end of the current script. That's how it works. And then it will just, yeah, pause it as HTML. Disgusting. Disgusting. But for this case, it was actually quite, it was actually quite useful. I was quite happy with it. Anyway, have you seen this type of thing before? Of course I have. It's disgusting. It is. So what is happening here is they're trying to load like jQuery from some sort of CDN where, you know, in the hope that it will already be cached because they've used it on a different site or whatever. But some countries don't have access to particular CDNs or sometimes the CDN is down or something. So you end up with this little script block here going, well, if jQuery is not there, then I'll load it from my own server instead. Document.write. They could be using either adjacent to HTML, shouldn't they? They should be using, well, the problem with that is that would behave differently because that wouldn't load the script synchronously. In async. It would be an async script. Yeah. So that's why they use document.write which is horrible. We've got little script escape again, through and a different version of that there. So, I'm less excited about this feature because my response to this would be don't load jQuery from CDN. Just load it on your own server because then you're not going to have the... Especially if Safari already double keys their caches. Like, no other site can put something in the cache for you on Safari anyway. Don't rely on it. Yeah, and Chrome as well is doing the double key thing. And you're going to hit another connection setup time for this. Yeah. Okay. We think it's bad. But do you know what? Modules. Let's talk about it. They've got maps have a solution for this. As I say, I'm not massively excited about it, but what you can say is, you know, jQuery and you can give it two URLs. Also, we'll try the first and if it fails, we'll use the second. Yeah. All right then. Fair enough. Yeah. It's in there. So I just wanted to mention it. Here's one I'm a little bit more excited about. Oh, it's a rollercoaster of excitement. Isn't it? So here I'm loading, like, I've got foo, which is pointing to foo version two. Oh, because we have past version one now. Past version one of foo. I'm also using comlink. What? God, man. Comlink also uses foo, but it expects version one. What are you going to do? There. It goes faster. It goes faster. That doesn't work. That doesn't fit. Shut up. Right. In this situation, here is what you would do. You've got this scope section where you can say you're essentially providing exceptions to the import section. So for any modules that are under this directory, like onwards that have that sort of URL prefix. Well done them that they thought about this. Yeah, exceptions. So is that something that we think will happen that, you know, libraries will stop bundling their dependencies and just leave them as like raw identifiers and leave it up to you as the final app developer to actually, you know, bend the arrows the right way that every import points to the actual correct file. I think that's the dream. I think the dream is to find a way to turn node modules, turn the node resolution system into something that can be described by this import map. Yeah, I guess we would expect bundlers to output this for us. Yes, absolutely. Because they already do the whole analysis and do everything. It's like, you know, here's your import map. Just put it in your HTML. I think those libraries already exist. Like people have experimentally gone and like, you know, we can generate an import map based on the project structure. I know that the rollup bundle object pretty much contains all the data we need to do this. Yeah. Yeah, so it's easy. It's easily done, which is great. Yeah, we, you know, whether a human would be writing this or whether it would be generated by a bundler, who knows. Final thing, and this is one of the things I'm actually most excited about. Oh boy. Import scheme. Right. Oh, so that basically says to any old element that takes URLs can now take something with an import scheme and if we look it up in the map, is that what is happening? That is it. That is exactly it. It's anything that can support URLs. So it's the same thing then that I can prevent and validation of the entire resource. Okay, here. Works in CSS background images. Works anywhere. Oh yes, it's a scheme. So anything. It wouldn't even work in fetch. Yes, yeah, absolutely. Yeah. Ah. So there is a slight problem with like relative URLs because especially if you're in CSS land, it knows it's relative to the CSS file because that's how referrals work in CSS. But if you're in a script and you do fetch your, and you get relative URLs relative to the document. I'm going to derail this for a second because I've passed drive me mad on the web. I have, I like that roll up when you like bundle it, everything just ends up in a root folder. There's no folders anymore. There's no sub directories. Everything is just dumped into one directory and there's no clashes because they have hashes in the file name. It makes things easier. I would say for anything that is not going to be user-visible, I would tend to agree. Yeah. I like, obviously we like good URLs. Right. For things I would appear in the URL bar. You shouldn't sacrifice that. But basically I have subfolders for the index HTML to my blog post. But all the images in the blog post are back in the root folder. Absolutely. So every URL is just, every image include is just a slash something something. Yep. And it makes things simple. But it means in cases where it's going to be relative to your document rather than relative to the module, the proposal is to have something like import.meta.resolve which will take a relative URL and it will do it relative to the module rather. You could even do things here. Like this is actually really good for like progressive enhancement when you want to do like, oh, does this browser have WebP support and you can bend the import the right way? I mean, we have picture element and everything. I know that. Yes. But now you have programmatic control over it. Well, do you know what? I'm glad you said that because I've realized there was a little bit. I was going to talk about earlier and I forgot in terms of progressive enhancement, this model where you're saying like map like food.mgs to the hashed version, you could ship this to browsers that don't support import maps as long as you also have food.mgs on your server. So you would have this URL, this on your server, which has the full caching headers. Yeah. And then you would have this on your server as well as a fallback which had no cache. Yeah. So an old browser aren't excluded. They get a kind of, worse loading performance. Yes. But they're not excluded. Like the thing still works. So like maybe when it gets to like most browsers have this but some still don't, then that's a switch point and you've got a progressive reading tool. Yeah. I'm really excited about this. I'm sure it will change a little bit before it reaches browsers properly. I think it's very important. Like this is not happening yet. This is an experiment. Like at this point it's in Canary. It's unstable because we have an origin trial but it's not enabled and stable by default. Yep. There are still standards going on. There is a discussion going on. We should link to the proposal and stuff so people can weigh in if they want to. And again, we're looking for developer feedback on this. Do you like it? Do you hate it? What do you like? What do you hate? What do you think should be different? And now is the right time to be letting us know. Yeah. All of that stuff. Weigh in. Don't pretend like you have muscles. Thanks mate. He's got like strong fingers. He's typing fingers. Every day. Everything else is just rot. That's it. I can't.