JAKE ARCHIBALD: Well,
should we do an episode? And then we can maybe try
and do some of a [BLEEP] at the end for
Lucas to cut around. CREW: Yup. Rolling. We are rolling. JAKE ARCHIBALD: OK. All right, where am I? SURMA: What? What? [LAUGHING] [MUSIC PLAYING] JAKE ARCHIBALD: So we spent
the last couple of episodes talking about real things. Real talk. SURMA: [LAUGHS] Let's stop that. Let's not do that. JAKE ARCHIBALD: 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 in the early messing around phase. SURMA: Right. So yeah, let's give it context. Because I've seen we
have an article on this. We have had a confusion about
how stable certain features are when we announce them. JAKE ARCHIBALD: Right, yes. SURMA: Where is it at? JAKE ARCHIBALD: Well, yes. SURMA: [LAUGHS] Yes. JAKE ARCHIBALD: 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 in production, in production with the
whole origin trial thing. SURMA: But none of
this is set in stone, so it could still change-- how it works, why it works. JAKE ARCHIBALD: Yep. This episode could be
completely useless by the time it goes out. SURMA: So I guess it's also
pretty much Chrome only then at this point? JAKE ARCHIBALD: It is, yeah. SURMA: Any other browsers
have it behind the flag? JAKE ARCHIBALD: Nope, nope. SURMA: All right, it's just us. JAKE ARCHIBALD:
It be Chrome only. So what is it? 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 module
imports with your-- SURMA: It's got a library? JAKE ARCHIBALD:
--module scripts. See? I used your library. SURMA: That's nice. JAKE ARCHIBALD: See? You happy? SURMA: You didn't use
[INAUDIBLE] for once. JAKE ARCHIBALD: No, no, I
changed it up this time. But a lot of us are more
familiar to seeing something like this. SURMA: Because that's how
the node import works, and most of the
bundle of support that kind of specifier
where you just say, just put the node
package name in there, and we'll resolve the rest. JAKE ARCHIBALD: Yes. 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 directories that have node modules alongside-- SURMA: It goes upwards and
tries to find the closest node-- JAKE ARCHIBALD: No, no,
it'll find them all. SURMA: Oh, really? JAKE ARCHIBALD: Yeah. SURMA: That's a twist. Cool. JAKE ARCHIBALD: It goes
and finds them all, and then it will find-- SURMA: So you'll put a node
modules folder in slash, like in the root
of my hard drive? JAKE ARCHIBALD: I
think that will work. SURMA: That's amazing. JAKE ARCHIBALD: Yeah. But then there's also
the special global one for your global modules, so
that goes at the end as well. SURMA: I didn't
know that existed. JAKE ARCHIBALD: Well, yeah,
if you do NPM install dash g, goes in your global stuff. SURMA: Yeah, you're right. I never thought about that. JAKE ARCHIBALD: Yeah. Yeah, yeah. And then it will iterate
through all of those, and it will look for a
directory called comlink in each of those. SURMA: And if there's multiple? JAKE ARCHIBALD: Well, so it's
going through them closest-- SURMA: In order. JAKE ARCHIBALD: Yes. So when it finds comlink in
one of them, it will go, right, does this have a package json? 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 any
good, I'm going to try and load index.json. If that's not there, I'm going
to try to load index.node. SURMA: Really? JAKE ARCHIBALD:
For binary modules, yes, yes, that's how it works. And if they're not there, it
then goes up the directory's-- SURMA: It makes sense. Yeah, OK. JAKE ARCHIBALD: --yeah,
and off it goes. SURMA: We want that on the web. Is that what you're saying? JAKE ARCHIBALD: And that's the
problem is we literally cannot do that on the web, because
imagine how many requests it would have to make-- SURMA: It'd be great. JAKE ARCHIBALD: --just
to find script, right? SURMA: Time to interactive,
two and a half years. JAKE ARCHIBALD: Yeah. [LAUGHING] 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. SURMA: Oh, it's a new type! JAKE ARCHIBALD: It's
a new script type. SURMA: Can it also
put in a file? JAKE ARCHIBALD: Yes. Yes, you can, and you shouldn't. [LAUGHING] And we'll get onto why. But this is what it looks like. You'll recognize it. SURMA: So it's literally a map
that maps from the identifiers to-- oh, that's interesting. Because I remember
that there is a rule for both dynamic
and static imports that they have to
start with slash or with a relative
or absolute path. JAKE ARCHIBALD: Yes. SURMA: They're not allowed
to start with like this. JAKE ARCHIBALD: Yes. Modules on the web right now
have to start with a dot. I think it has to be,
like, dot, dot, dot-- it's dot slash? Dot, dot, slash? SURMA: I think it's slash. Otherwise it could be-- JAKE ARCHIBALD: Or a
valid URL, or slash. Right? SURMA: Right. OK. JAKE ARCHIBALD:
Something like that. SURMA: OK. JAKE ARCHIBALD: And so this
would let you with this. Now you would just be
able to reference-- SURMA: It leaves this open for-- oh, cool. OK. JAKE ARCHIBALD:
Reference comlink and-- SURMA: So there is no way that
an import map identifier could clash with existing
production code out there right now
because of that rule? JAKE ARCHIBALD: Ah,
hold on to that. But yes, as long as you've
got this, one of these has to go before anything that
imports anything, any impulse 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. So this ideally right in
the head of your document before everything else. And this is where you define
where we shouldn't put them in the file. And that's why you probably
shouldn't put them in a file. But yes, now this works. SURMA: Neat. JAKE ARCHIBALD: Just works. Thank you for spoiling my
next slide multiple times. This just goes to show we
don't rehearse this, right? Yes, I would say
you can do this. It has some special
MIME type, but yes, you shouldn't, because then
you've got this head of line looking thing. SURMA: So will that mean that a
script type import map is also deferred by default? Because modules are
deferred by default. JAKE ARCHIBALD: 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. SURMA: Script tags. JAKE ARCHIBALD: That are using-- SURMA: So basically, if
you put it in an XML file, but put the script take high
up, you should still be fine? JAKE ARCHIBALD: But it's
one of those things-- SURMA: [INAUDIBLE],,
but you should be fine. JAKE ARCHIBALD: But
there's a reason we inline scripts, right? Because if it's a very
small file, then the amount you pay for that
request and response-- SURMA: Will it stay small? Will people really
keep small import maps? I kind of expect them to
be like [BLOWS RASPBERRY].. JAKE ARCHIBALD:
That is a question. And yeah, and it
would be interesting. So maybe if 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 the example we had before. I can import comlink because
it's in the import map. SURMA: That's the thing
that usually works in node. JAKE ARCHIBALD: In node
land, you would have-- yep. This works as well. SURMA: Really? JAKE ARCHIBALD: You do
something like this. So there's is a special rule. If the thing ends
in a slash, then you are defining a prefix
for all of those. SURMA: Oh, that's really nice
that they thought of that. JAKE ARCHIBALD: Yes. SURMA: Because I
would have expected that I'd have to define-- JAKE ARCHIBALD:
Every single one. SURMA: --like do static,
analyze all the inputs 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, and index is assumed,
like, it is a node? JAKE ARCHIBALD: No. Index is not assumed. And also, things-- like in node,
you can miss out the extension. SURMA: Oh, yeah. No, I mean, that wouldn't just-- JAKE ARCHIBALD: You
could use import maps to work around that. But you would have to do
every single file and-- SURMA: Right, because basically
you have to define everything. It's like here's the thing
without the extension that maps to the thing
with the extension. JAKE ARCHIBALD:
With the extension. Yes. So you can do that,
but probably don't, unless you for some reason
know of a way around it. You can do this. SURMA: Oh, so maybe
I can do rewrites. JAKE ARCHIBALD: Yes. SURMA: So something that is
already a valid import path, I can now say, you know what? It's actually here. JAKE ARCHIBALD: Yes, absolutely. SURMA: Oh, that's neat. JAKE ARCHIBALD: And you could
say that this could just create a lot of confusing
code while your scripts are doing one thing. SURMA: Oh, yeah, 100%. JAKE ARCHIBALD:
But I think there's a really interesting
use case with this that I'm really excited about. So here's an example import. But in production, it will most
likely look more like this. SURMA: Yes, because
at least it should be. Because good caching--
you need this. JAKE ARCHIBALD: You need
your unique file name. So then if you change
the file, you will-- watch this-- boop! There you go. Change the hash. SURMA: Oh, I set
you up for this one. JAKE ARCHIBALD: I
know, it's great. Yeah. SURMA: It's so good. JAKE ARCHIBALD: And then it
means you've changed the file. So each of those resources
can cache forever, because you changed
the file when you were changing the content. But the problem with this
is you've now also changed the content of the parent file. SURMA: Yes. JAKE ARCHIBALD: So you need to
update the hash of that file. SURMA: Yeah, and if
nothing else changed, people will download
a file that is exactly the same except for the imports. JAKE ARCHIBALD: Yes. SURMA: And now with
the import map, I see where you're
going with this. JAKE ARCHIBALD: Yes. So even with a
small module change, you end up invalidating
massive tree-- SURMA: Potentially-- JAKE ARCHIBALD: --the whole lot. SURMA: --always from
where you did the change to the root of your
thing, at least that one branch,
potentially more. JAKE ARCHIBALD: 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. SURMA: Oh, that's very nice. JAKE ARCHIBALD: So that
means if you change foo-- we just changed foo. Watch. Boop! There you go. SURMA: And so the
interesting thing is this wouldn't be
possible with HTTP redirects or rewrites. Because it wouldn't
hit the HTTP cache. JAKE ARCHIBALD: Exactly. SURMA: You could do it may be
in a service worker, I guess? JAKE ARCHIBALD: You could
do this in a service worker. You could insert
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. SURMA: Yeah. That's a really exciting use
case, actually, for this. JAKE ARCHIBALD: I
think it's great. And so that means, yes,
the user will obviously have to download the new
foo blah, blah, blah, blah, blah, but-- SURMA: But only that. JAKE ARCHIBALD: --only that. Only that small change. SURMA: And the entire
rest of the pipeline can still just
rely on-- you know, has to load all the static
imports before executing. So everything will just
work and keep working. JAKE ARCHIBALD: So 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-- SURMA: Oh, they're
actually invalid. I didn't catch that. I thought that just,
like, the models above it wouldn't respect them. JAKE ARCHIBALD: No, it
will error and ignore. SURMA: Actually, that's
probably a good idea. JAKE ARCHIBALD: Yeah. So it won't error modules. It will just error on
the script elements. SURMA: You see an error
that there was an-- that this is not in
the correct place. JAKE ARCHIBALD: And
it will ignore it. SURMA: But it will also let the
other things that have invalid import statements error out. JAKE ARCHIBALD: Yes. SURMA: OK. JAKE ARCHIBALD: But you can
still create them dynamically, as long as you're still
creating them dynamically before any of your imports. And I think this is
really cool, because you could have something like this,
where it does a feature test. And it could be a
new JavaScript thing, could be a new DOM thing. SURMA: Oh, that is really cool. JAKE ARCHIBALD: New
JavaScript syntax. And you could say,
right, now dump out one of these import maps. Instead of loading
main, load main modern. SURMA: So for
example, I could say do you have readable stream
transforms in writable stream? If I do, I'm just going
to create this redirect to a small file
and just re-export the native applications. If not, load the entire
polyfill thing in my code, and just import
one normal module. JAKE ARCHIBALD: Yes. SURMA: And that will
get the polyfill if it needs to be one,
otherwise it won't be. JAKE ARCHIBALD: Exactly that. SURMA: That's really cool. JAKE ARCHIBALD: 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, direct it to another file,
which makes use of that, and therefore doesn't have to be
transpired, that kind of thing. SURMA: Could be smaller. JAKE ARCHIBALD: Could
be smaller, hopefully. SURMA: So why did you do this? JAKE ARCHIBALD: [LAUGHS]
Do you know why I did this? SURMA: No, that's
why I'm asking. [LAUGHS] JAKE ARCHIBALD: Well, come
on-- we do this show and-- SURMA: Well, we do this-- [MUTTERING] JAKE ARCHIBALD:
Sometimes we make believe on this show a
little bit just for the chat. SURMA: No, I legit-- I guess it has to do with
some sort of escaping, but I didn't-- JAKE ARCHIBALD: It is. SURMA: Because this is
just a normal string. This is like the
only part where you make use of the template
literal packets. JAKE ARCHIBALD: Yeah,
the HTML compiles it. 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. SURMA: Oh, that's the thing. Yes. Yes. I remember now. JAKE ARCHIBALD: Yes. SURMA: Even in a string
literal, you can't just have angle brackets slash
script, because by the time your file gets parsed,
the parser will be like, yep, script ends here. JAKE ARCHIBALD: Yeah, because
this is HTML parser time rather than JavaScript parser time. So yeah, you've always got to
do something to work around. SURMA: 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. JAKE ARCHIBALD: Oh, I
love insert adjacent HTML. SURMA: I always
do create element and set an HTML something. JAKE ARCHIBALD: 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 five, five,
five or something. It was in that era somewhere,
but they standardized it because it is actually a
pretty useful, very weird API. You can see I want it
to go after the end of the current script. That's how it works. And then it'll just,
yeah, parse it as HTML. SURMA: Disgusting. JAKE ARCHIBALD: Disgusting,
but for this case, it was actually quite useful. I was quite happy with it. Anyway, have you seen
this type of thing before? SURMA: Of course I have. JAKE ARCHIBALD: It's disgusting. SURMA: It is. JAKE ARCHIBALD: So
what is happening here is they're trying to load
jQuery from some sort of CDN 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, like hey, you're going well. If jQuery's not there, then
I'll load it from my own server instead. SURMA: Document.write. They should be using insert
adjacent HTML, shouldn't they? JAKE ARCHIBALD: They
should be using-- well, the problem with that is
that would behave differently, because that wouldn't load
the script synchronously. SURMA: Oh, it would be an async. JAKE ARCHIBALD: It would
be an async script. So that's why they
use document.write, which is horrible. We've got a little script escape
again in 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-- SURMA: Especially--
Safari already double-keys their caches. No other site can put
something in the cache for you on Safari anyway. Don't allow it. JAKE ARCHIBALD:
And Chrome as well are doing the double-key thing. SURMA: Yeah, don't. JAKE ARCHIBALD: And you're
going to hit a connection setup time for this other-- SURMA: Yeah. JAKE ARCHIBALD: OK,
we think it's bad. But do you know what? SURMA: Let's talk about it. JAKE ARCHIBALD: The [INAUDIBLE]
maps have a solution for this. As I say, I'm not
massively excited about it. But what you can say is jQuery,
and you can give it two URLs. SURMA: Also, we'll
try the first. And if it fails,
we'll use the second. All right then? JAKE ARCHIBALD: Fair enough. It's in there, so I just
wanted to mention it. Here's one I'm a little
bit more excited about. SURMA: Oh, it's a roller
coaster of excitement. JAKE ARCHIBALD: Yeah, I know. It's just brilliant, isn't it? So here I'm loading foo, which
is pointing to foo version two. SURMA: Oh, because we
are past version one now. JAKE ARCHIBALD: Past
version one of foo, but I'm also using comlink. SURMA: Good man. JAKE ARCHIBALD: But
comlink also uses foo. But it expects version one. What are you going to do? SURMA: Ghostbusters? [LAUGHING] JAKE ARCHIBALD: Ghostbusters? 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'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. SURMA: Well done them that
they thought about this. JAKE ARCHIBALD: There
are exceptions there. SURMA: So is that
something that we think will happen, that
libraries will stop bundling their
dependencies and just leave them as raw
identifiers and leave it up to you as the
final app developer to actually bend the
arrows the right way that every import points
to the actual correct file? JAKE ARCHIBALD: I
think that's the dream. I think the dream is to find a
way to turn the node resolution system into something that can
be described by this import map. SURMA: Yeah, I guess you
would expect bundles to output this for us. Right? JAKE ARCHIBALD: Yes, absolutely. SURMA: Because they already
do the whole analysis and do everything. It's like, here's
your input map. Just put it in your HTML. JAKE ARCHIBALD: And I think
those libraries already exist. People have experimentally
gone, and we can generate an import map
based on the project structure. SURMA: Yeah, I know
that the rollup bundle object pretty much contains all
the data we need to do this. JAKE ARCHIBALD: Yeah. Yeah, so it's easily
done, which is great. Yeah, 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. SURMA: Oh boy. JAKE ARCHIBALD: Import scheme. SURMA: Right. So that basically says
so any old element that takes URLs can now take
something with an import scheme and it will look
it up on the map? Is that what is happening? JAKE ARCHIBALD: That is it. That is exactly it. It's that anything
that supports URLs-- SURMA: So it's the
same thing then, that I can prevent invalidation
of the entire resource. OK, here. JAKE ARCHIBALD: Works in
CSS background images, works anywhere you can use URLs. SURMA: Nice. Oh yeah, it's a scheme. So anything. JAKE ARCHIBALD: Yeah, it
would even work in fetch. Yes, yeah, absolutely. Yeah. There is a slight problem
with relative URLs. Because especially if
you're in CSS land, it knows it's relative to the
CSS file, because that's how referrers work in CSS. But if you're in a
script and you do fetch, any relative URLs are
relative to the document. SURMA: I'm going to
derail this for a second, because paths drive
me mad on the web. I like that rollup. When you 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 record. There's no clashes because they
have hashes in the file name. It makes things easier. JAKE ARCHIBALD: I
would say for anything that is not going to be user
visible, I would tend to agree. Obviously, we like good URLs. SURMA: Right. You shouldn't sacrifice that. JAKE ARCHIBALD:
There are things that have got to appear in the URL. SURMA: But basically
what I have, I have sub folders for the
index HTMLs of my blog post, but all the images
in the blog post are back in the root folder. So every URL, every
image included is just a slash something something. JAKE ARCHIBALD: Absolutely. Yep. SURMA: And it makes
things simple. JAKE ARCHIBALD: But it
means that 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 route. SURMA: Cool. You could even do things here. Like, this is
actually really good for 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. But now you have
programmatic control over it. JAKE ARCHIBALD: Well,
do you know what? I'm glad you said that,
because I 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, foo.mjs
to the hashed version, you could ship this
to browsers that don't support import
maps as long as you also have foo.mjs in your server. So you would have this
URL, this on your server, which has the full
caching headers, and then you would have
this on your server as well as a fallback,
which had no cache. SURMA: So old browsers
aren't excluded. They can have worse
loading performance, but they're not excluded,
like the thing still works. JAKE ARCHIBALD: So maybe
when it gets to most browsers have this but some still don't,
then that's a switch point, and you've got a
progressive enhancement. SURMA: This is really cool. JAKE ARCHIBALD: I'm
really excited about this. SURMA: So am I now, I think. JAKE ARCHIBALD: I'm sure it will
change a little bit before it reaches browsers properly. SURMA: Oh yeah. Yeah, I think it's very
important, like, this is not happening yet. JAKE ARCHIBALD: No. SURMA: This is an experiment. 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. 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. JAKE ARCHIBALD: And
again, I was going to say 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. SURMA: Win. [WHOOSHES] Don't pretend like
you have muscles. [LAUGHING] JAKE ARCHIBALD: Thanks, mate. [GROANING] I've got strong fingers,
these typing fingers. SURMA: Every day exercise. JAKE ARCHIBALD: Everything
else is just rot. [LAUGHING] Yes, that's it. I can't.