April 3rd, 2023 × #javascript#webdev#tooling
The New Import Map Standard
Explains the new import maps standard for aliasing files and paths in JavaScript projects. Covers how to use them and browser support.
- import maps explained
- aliasing paths
- aliasing node modules
- defining aliases in JSON
- import maps are like directions
- syntax thoughts
- import map syntax details
- distinguishing local vs external
- dependency resolution discussion
- bundlers discussion
- import maps work with bundlers
- standard across tools is good
- how import maps work in Deno
- import maps and DEPSTAT
- SemVer in Deno import maps
- standards over conventions
- Node package.json in Deno
- new filesystem API discussion
- filesystem API concerns
- filesystem API use cases
- Node and subpath imports
- getting subpath into Node
- Pathaliases in TypeScript
- Vite plugin for import maps
- tree shaking concerns
- integrity hashes concern
- integrity proposal
- ESLint resolver plugin
- VSCode auto import issue
Transcript
Announcer
Monday. Monday. Monday.
Announcer
Open wide dev fans, get ready to stuff your face with JavaScript, CSS, node modules, barbecue tips, get workflows, breakdancing, soft skill, web development, the hastiest, the craziest, the tastiest TS Webb development treats coming in hot. Here is Wes, Barracuda, Boss, and Scott
Scott Tolinski
ghee. Welcome to CIT Tax. On this Monday, hasty treat. We're gonna be talking about a feature that just arrived in pretty much the last of the browsers that it needed to arrive in, and we're gonna be talking about import maps.
Scott Tolinski
This may be something that you've seen around or heard around or maybe you've never heard about it, but it is, you know, it's related to the new JavaScript ESM syntax. So we're gonna be talking all about what import maps are and more. My name is Scott Talinski. I'm a developer from Denver. With me as always is, Wes, the hot tips boss.
Wes Bos
Yeah. I just got this, new, like, neon it's not neon, but it's LED, but looks like neon sign in my office,
Scott Tolinski
and it's so cool. I'm so happy with it. Yeah. Hey. Isn't isn't that like a wonderful technological advancement that We don't actually have to have real neon Yeah. Anymore. You could just do LEDs and have it look the same. I mean, LEDs, Like, really, I I know it's probably not low key, but, like, have completely transformed the world in so many ways. Everything.
Wes Bos
Everything. Yeah, it's so good. The only thing I don't like about LEDs is that light fixtures are just garbage now whenever they whenever they die, right? They can't replace the light bulb. They're just disposable.
Wes Bos
Yeah, yeah. I'll take it for the energy savings and the ability to literally put them in anything. Yeah, totally. And they dim they dim decently well, too, depending on what you get. Yeah, it's I went through that with my office It's like there's like a weird combo of high quality lights and high quality dimmer switches. Mhmm. And you should never cheap out on either of them. Yeah. Or else you're gonna have some. The other is a buzz like I have we put some in. They don't turn off completely. They don't dim correctly.
Scott Tolinski
A lot of things. Yeah, yes, annoying.
import maps explained
Wes Bos
But let's, let's get into import maps here. This is something that has just dropped in Safari Technical Preview. Now they're in all the browsers. I thought we would do a quick show explaining what they are, how you use them, what they what they look like and like what about TypeScript, Deno, Node, all of that stuff as well. Yeah, that sounds lovely.
aliasing paths
Wes Bos
Import maps. This is actually going to be really helpful for, I think, probably everybody listening. They are the ability to define, I'm going to call them aliases for paths in your project. So if you have like Utils. Js or you have a folder called DB and you got 6 or 7 files in there.
aliasing node modules
Wes Bos
Often when you're requiring files. You got to do that dance where you go up 2 levels, over 2 levels, and down 3 levels. And it's kind of annoying, right? And Scott has said himself for a long time, you've been using the, what, the TypeScript version of this where you just have the at in front? Yeah. And and it's mostly Vite at this point. And and, honestly, the way that SvelteKit does it is really neat where you add your aliases in the SvelteKit, And then it generates all the TypeScript
Scott Tolinski
config you need, and it generates the Vite config that you need. So that way, you only have to write it once. In the past, I was having, like, a separate Vite and a separate TypeScript just to get them both on the same page. But, yeah, I've been using, aliased imports for a long time because, like you said, that whole song and dance about having to Recognize where you are and where you're going. And if you move a file, sure, Versus Code 9 times out of 10 these days will update your paths correctly, But sometimes it won't, and sometimes it can be frustrating that it doesn't do that. Or sometimes you end up with a forward/.forward//.forward/.forward.
Scott Tolinski
Like, you just just this long, long, long path. You've dialed it in. So this just makes everything cleaner. They feel like internal modules is really what they feel like. Yeah, exactly.
Wes Bos
So this is a new web standard. It's in all of the browsers and you will be able to specify either a folder files so you could alias utils to.
Wes Bos
Forward Slash. Forward Slash.
Wes Bos
Whatever.
Wes Bos
Oh, and then you can also you can alias. And this is super helpful, especially in Deno ESM world. You can alias HTTP paths. So if you have a file on a CDN somewhere that you want to import, then you don't have to say Import react from httpcolon/esm.
Wes Bos
Sh or unpackage or ESPN. Like there's all these like CDNs out there that will host all of NPM for you and you can require it directly for it from it because that's part of the mspec that you can just import stuff from a URL.
Wes Bos
However, it's annoying, especially if you have to do that through 8 files. You know, then that file name has the package number in it, and that gets kind of unmaintainable.
Wes Bos
So the solution to all of this is an import map where you declare a little bit of JSON in your application.
Wes Bos
And you say, okay, when I import things from these names like raw, Just like I import whatever from React or import whatever from Svelte. If I want to import something from a local file or a remote file. I can just use that URL and the browser will know to look at the import map and say, They use the word utils or money or svelte here, but I know to actually go get it from this local or remote file.
import maps are like directions
Scott Tolinski
Yep. And and one thing to, you know, think about in the term map here. Right? We have an important map. You'll hear the word map in programming a lot. And it's almost always kind of like a map is is almost like a direction to somewhere else or or that regard. Right? You have, what are they? What are the, source maps? Right? Yeah. A source map is basically a map to show you from your compiled code to your non compiled code and this is basically a a direction to say hey here's a path And this is the path that you should resolve. It's basically telling you where to go at any time so you can just keep that in your brain is like, hey. I'm I'm looking at a map here. That's what these things are doing.
Scott Tolinski
How do you feel about the syntax for this thing, by the way?
syntax thoughts
Wes Bos
It's good.
Wes Bos
So it's Mhmm. It's JSON.
Wes Bos
Yeah.
Wes Bos
And Yeah. You open up a pair of curly brackets. I don't love writing JSON, but I understand why it's JSON because it has to be statically analyzed, right? Like, it can't be programmatically imported or whatever. So open up curly brackets, you have the keyword import.
import map syntax details
Wes Bos
And then inside of that, you have your keys are going to be your like aliases, and then the values are going to be either local or HTTP paths where it can go. I even wonder if you could do like like a like if you had a floppy disk that would that work? I should get I should get a floppy disk for my to Thunderbolt and try plug it in and put some JavaScript on the floppy to see if I can a good alien
Scott Tolinski
ESL. I don't see why you couldn't. I mean, this is a bad. Right?
Wes Bos
Yeah. At floppy?
Scott Tolinski
Yeah.
Scott Tolinski
At floppy. Yeah. That's great.
Wes Bos
That that's actually another a good point is that a lot of people will like to note them with a use what? An at sign at the front? Yeah. I use a dollar sign. Okay. And then that's just kinda convention I picked up from SvelteKit specifically.
distinguishing local vs external
Scott Tolinski
I've done several different things. Sometimes I've done an at sign.
Scott Tolinski
Sometimes I've done like a at level up even though that's like Feels like it's an NPM package, which is why I've moved away from that.
Scott Tolinski
Anything that you can do to distinguish your local paths your local module paths from, you know, external ones is going to be like a win for clarity when you're working in your code because what you don't wanna do is you don't wanna be looking at these maps and say, like, alright. Is this a is this a, a package coming in from NPM. Is it coming in from something local? Is it map from somewhere else? You know, you can have a system. The dollar sign does work really well. I have, like, dollar sign utilities, dollar sign DB, dollar sign types. You know? I have have those things set up, and it it, For the most part, it's it's done very well for me in terms of being able to recognize what's local and what's not. Yeah. I I also I forgot to say the JSON of the import map goes into a script tag with the type of import map in it. So this is something you define in your HTML.
Wes Bos
It's generally your entry point to your application and you put that in there and then any scripts that are loaded on that page will know to use that import map when when running it. And this is because strictly because, you know, this thing works without
Scott Tolinski
bundlers, without package.json.
Scott Tolinski
It works just straight up in the browser because you can now use imports in e s m just straight up in the browser. So there has to be a way to define it that the the browser can understand easily. So that that's why that is like that. In case you're wondering. Another question that a lot of people have is like, what about
dependency resolution discussion
Wes Bos
dependency resolution? You know, like if you think about like, okay, this is great or if you get a utils file. But like, what if I'm already using node packages and whatnot? Some packages will publish a version that has like no bundled version. And then also when you do your bundling, You can set modules to be external. So meaning that if you don't want your or ESBuild or whatever to actually bundle the dependencies and say just look them up yourself, Then you can mark them as external, meaning that it won't include them as part of your final package. And it's saying I'm going to leave this up to the browser or the the JavaScript runtime to figure out where those specific things are. Yeah. So kind of back to
bundlers discussion
Scott Tolinski
what we're talking about with package.json or or, you know, modern JavaScript.
Scott Tolinski
Like, what about, like bundlers. Right? The so much of our work these days has been around needing a package manager, needling a needing a bundler to resolve those packages and bring them in and bundle your code together so that it all works. Does this mean that we, can now just use import maps and bring things in from package dot or or node modules folder directly without having a a bundler that
Wes Bos
compiles it all and brings it all in for us. Yeah, I made a TikTok on this and I said, like, we're probably a long way away from not having to use a bundler, but this is Certainly a step in the right direction. Yeah. It's a step. I don't know if that was the right thing to say because the more I thought about it and the more I got feedback on it, people Sort of saw this as like this is an alternative to a bundler. And in reality, this works just great with all of your tools and all of your bundlers and everything. It's just a way for you. It's a standard way to define what your aliases and what your import lookups are going to be in your JavaScript code. And whether you run that raw in the browser, which works great, Or whether you actually do end up running it through a bundler, it still is very nice to be able to alias these things in your application. So I probably don't see this as a bundler versus not bundler thing, and I probably should have worded that a bit different. I think it's more of a this is a standard to define how things are looked up.
import maps work with bundlers
Wes Bos
And isn't that great? Because now
Scott Tolinski
any tool and raw browser can use that. Yeah. I mean, ultimately, though, it does it does mean that There are some instances in which in which you might use a bundler before that you might not have to know especially for early projects, small projects, little hacked together things you wanna throw together something and just toss in an important map to resolve some of your dependencies like that. That seems like that that's totally a fine thing to say. I mean, I don't I don't get the pushback on that. But Yeah. Yeah. Totally. And, like,
Wes Bos
eventually, maybe we will be at a spot where we don't necessarily need the bundler.
Wes Bos
Like, what is 1 spec that is a browser standard that made all of our tooling better? ESM, right? ESM is a web standard.
standard across tools is good
Wes Bos
And even though we still use all of these amazing tools like Parcel and Vite and Webpack. They all picked that up and made it part of their tooling chain. And isn't that beautiful that we have a standard across it. So wouldn't that be nice if we had a standard for aliasing across all of these tools? Absolutely.
Scott Tolinski
And all of those things they they made our our bundles that brought their their whole development process faster because, you know, the computer is having to do less for us now because the the browser can do a little bit more. And not not to say that this will do that, but, you know, who knows? Maybe maybe, it will open up some improvements our tooling that we can just take advantage of in our our day to day work. So let's talk about, using this with things like Deno and Node. Now I I've Actually, Wes, I just started a new project, and I used I chose Deno for it, just because you know, I wanted to write some TypeScript. I wanted to get it up and running quickly, And I wanted to just give Dino a a quick try, and I was so pleasantly surprised. Well, not pleasantly surprised. I I just say, Pleasantly, enamored with how nice the experience of working in Deno was. I was like, this is great. I I think I, you know, I think I would, start any small new project using the same kind of flow.
how import maps work in Deno
Scott Tolinski
So how do these things work with Deno? Is it is there anything fancy here that we have to be aware of? So
Wes Bos
Deno uses the import map spec as well, which is awesome. So, again, another win for Deno being web standards based.
Wes Bos
It goes into a file called importmap.json, and that will that will be looked up when you run your application via Deno. So that's awesome because it's there. So if I were doing this In a project that was server and client, I probably would just put it in importmap.json and then I would just pull that into my HTML template as part of my render, right? Because then then you can just have it in 1 file and pull it in wherever you want. Does this do away with the whole DEPstat
Scott Tolinski
TS thing in Deno?
import maps and DEPSTAT
Wes Bos
Yeah, it does. And for the longest time, that's kind of what I thought would be the package. Json of Deno is just you import something from a URL and then immediately export it or export from HTTP blah blah blah. But It's essentially your your package. JSON is essentially your import map where you are giving it a list. And also one further is Deno supports the npm colon prefix in import maps. Mhmm. So what you could do is your import map is instead of having to install something, you just npmcolon react, npmcolon svelte. And that you should probably put the SemVer version on the end as well because you shouldn't just be locked versions.
SemVer in Deno import maps
Scott Tolinski
Yeah. Yeah. Yeah. Yeah. So those of you who don't know what we're talking about, in Deno, there's no package dot JSON. And so because tons of that. The way that people have been doing it for a long time is to simply just, like you said, import something from the URL and then immediately export it, because that's how import and exports work. And that's great. It works fine. But at the end of the day, you end up having 2 different ways of doing things in Deno world versus node world.
Scott Tolinski
And now with the import maps, if you wanted to have an import map take care of that for you, you could do a kind of the same way. But, again, you're probably just gonna end up Still using package.json.
standards over conventions
Scott Tolinski
But at at least with Deno now, you have a standards way of doing it rather than just this thing that people started doing out of necessity. Mhmm.
Wes Bos
Also another thing that Deno did roll out a couple of weeks ago is they now do support the node package. JSON. A Much to most a lot of people's Chagrin? Like, grimace. Yeah. What's it what's it called? I think it's chagrin.
Node package.json in Deno
Scott Tolinski
Che Grin. Let me Google this. Chagrin. Yes. Oh,
Wes Bos
s c h a g r I n. Disappointment or anger, especially when caused by failure or mistake.
Wes Bos
Mhmm. And they have to kind of do that in order for people to move over from node More easily. So now they support it. But it's kind of tricky with the with the Deno stuff because you you look at it, you'll get, okay, I want it to work in Deno. But I also would like it to work in node.
Wes Bos
So do I just use node code? Do I just do everything in node and then run it, Indino?
Scott Tolinski
Yeah. Right. Well, I guess maybe. Yeah. Right? Hey.
Scott Tolinski
Right. Then it's at then at least you could choose where you're running it, I suppose. Is Node the new standard?
Wes Bos
It might be. I was I was actually looking into that with the, what is it, the new file system API.
Wes Bos
There's like a new file system API that's in all the browsers now.
new filesystem API discussion
Wes Bos
And it's just like, well, Shouldn't we have that in Deno now so that if I want to write a file, it would be it would work in Node? Because like now if you want to write a file, you have Do it in like a Node API or the Deno API or the Browser API.
Wes Bos
It would be nice to have like 1 API. And now there's a new there's a new spec for that. And I've written a couple of notes in the winter CG, which is the working group, And they're thinking about it. So apparently, it's like not fully fleshed out yet or it's like not doesn't cover all their use cases, but It would be nice to eventually again, like this import maps will have 1 standard file system API
filesystem API concerns
Scott Tolinski
browser and all the JavaScript runtimes. The the the file system API. Are you is it is it like what you would use in the browser for accessing the user's local file system? Is it that same API? Or
Wes Bos
Yeah, it's the What WGFS.
Wes Bos
Let me I'll link up the the winter CG proposal.
Wes Bos
But, yeah, it's for accessing, I think, either a sandbox file system in the browser.
Wes Bos
Mhmm. I think that's what it's for, not specifically for accessing the actual user's file system. Maybe it is. I have to look into it a little bit more. It was just just approved. Okay. Yeah. Oh, it was just approved. I was gonna say because there is that that,
Scott Tolinski
file system API in the browser already that I've done a little bit of work with and it's really neat to access the user's local file system.
Scott Tolinski
And I was wondering if this is the same one. I'll have to dive in. Yeah. I'm just reading the winter CG
Wes Bos
where I added it because the other thing people are saying like, well, Cloudflare is part of the winter CG, but Cloudflare doesn't have a concept of a file system.
Wes Bos
Right. There's no file system in Cloudflare. If you want to save something, you said you send it to a service.
filesystem API use cases
Wes Bos
So, like, how would that work? Possibly yeah. How could you
Scott Tolinski
does the whole thing blow up if you access the file system? Yeah.
Wes Bos
And like, how often in Node and Edge scripts and Deno scripts are you actually writing files to the file system? Usually not that often.
Wes Bos
But There's a whole all of tooling is writing file system. All the scripts I write locally to do things, that's that's file system. So it still would be nice to to have it.
Wes Bos
Anyways, let's keep going with node. So what about import maps with node? There is something in node which I didn't even know about until I started researching it. It's called subpath import, and it works very similar to how this works, except With Node, you must start it with a hash octothorpe hashtag is all the kids will call it.
Node and subpath imports
Wes Bos
And it works the same way in that you can alias files or directories in your note project. And this is actually super helpful. So it just goes in your package. JSON. It's called imports. Oh, yeah. Just like the spec. I've used this. Yeah. And then you could say like pound utils or hash utils is link to a JavaScript file or pound db star will be aliased to a DB folder and then all of the nested files inside of there, which is It's really nice. So it's almost the standard.
getting subpath into Node
Wes Bos
And then there are a bunch of threads and there's actually even some experimental code in there to look at getting this into Node, because if it gets into Node, the next thing that we're going to talk about is TypeScript.
Wes Bos
TypeScript has this thing called Pathaliases, which is what you're using, right? Totally. Yeah. So the Pathaliases is great, But it needs a bundler to properly work in Node. Js.
Pathaliases in TypeScript
Wes Bos
So it needs to be compiled. You have to do webpack or something like that. So if you're just doing straight TypeScript to JavaScript module.
Scott Tolinski
It doesn't doesn't work. Right? Yeah. And likewise, again, if you are using a bundler, you'll most likely need to tell the bundler,
Wes Bos
Like double define your aliases, right? Yes, exactly. That's what people are saying is that like, I have to set it up twice in like in my webpack or in my Vite again, and it could be a pain with just just doesn't recognize them.
Scott Tolinski
Oh, yeah, that's a whole thing.
Scott Tolinski
I guess that's another reason why v test is a thing. Right? That was, like, one of my whole things with the test for or jester's v test. It was like, I'm I'm my tests are not running the exact same config that my code is running, and that makes me very deeply uncomfortable.
Wes Bos
I should also say there are Vite, there's a Vite plug in to use your import map as well. Oh, really? It's great. So you feed that into your Vite config, which is again another reason why you should probably Put it in a JSON file so that you can easily import that and feed it into your vconfig.
Vite plugin for import maps
Scott Tolinski
Yeah, that's nice.
Wes Bos
Last Last thing we want to talk about is downsides to this type of thing. A lot of people say, what about X, Y and Z? Probably the biggest one people said is what about tree shaking? Because I Initially showed this as like a use it straight up in the browser.
tree shaking concerns
Wes Bos
And everyone says, Okay, but I'm not actually going to use that straight up in the browser because I need tree shaking and tree shaking is let's say you have a package with 7 functions and you only use 1 of those functions.
Wes Bos
Tree shaking will be smart enough to say, Okay, well don't include those other 6 functions in the final bundle. We need to keep it as small as possible.
Wes Bos
And the browser doesn't tree shake, right? The browser, the like multiple HTTP requests.
Wes Bos
To download a tree of JavaScript files is not an issue with HTTPtwo because the browser and multiplex the request. They can they can download all of those in one request, which is nice, but it doesn't tree shake. So The solution to that is, yeah, you probably still need a bundler to actually do your tree shaking.
Wes Bos
The other downside is there's no integrity, Which means integrity in JavaScript is saying every time you have a JavaScript file, there's like a hash that comes along with that file.
integrity hashes concern
Wes Bos
And if someone like if I had scott.com/cool.js and I was using that in my application, what's to stop Scott from swapping out the code on that file and gobbling up all my All my credit card payments or doing something malicious, right? So integrity means that when you load a JavaScript file. You also give it a hash.
Wes Bos
And if that hash doesn't match the file that's being downloaded because it's been changed at some point, then you know that there's some someone has been monkeying with the actual file, right? Like if you have version 1.2. Or there's just been a change in general. Yeah, but if that is true, then you should change the file path to be version 1.1.1 to 1.1.2.
Wes Bos
So if somebody actually changed But you should. Exactly. You, the developer, would have to manually go and do that instead of someone swapping it out from under you. So there's no way to do integrity with import maps.
Wes Bos
And In the browser, we have script tags with integrity. In Node. Js, we have package lock, which has hashes inside of it as well.
Wes Bos
So there is a proposal on how to get this working in import maps. I'll link it up in the show notes as well.
Wes Bos
Other downsides? I haven't looked into it yet, but my ESLint complains about not being able to resolve it. So there's probably some sort of ESLint plug in that will look up import maps. Let me search it real quick.
ESLint resolver plugin
Wes Bos
Oh, there we go. Hey, 57 downloads a week. Okay, so this is obviously very, very early on.
Wes Bos
It's called ImportMap ESLintResolver, meaning that like If you import something from a package, Esland will yell at you. It says, I can't find that.
Wes Bos
So this will look through your import map and and say, oh, I did find it. And it's because you used the import map. And then the Versus Code auto import. I also haven't looked into this, but It doesn't if you do the auto import, it does the straight up path.
VSCode auto import issue
Wes Bos
So I don't know how to make it work with
Scott Tolinski
Import maps. And that's the thing. It works really well with the Vite and TypeScript version of aliases, which obviously is the same thing, but it works really super well. Anytime I auto import anything. And that maybe not a 100% of the time, but 99% of the time, it finds my my package incorrectly uses their the import. And it's done that for a while too. It did that, back when I was using, not Vite. So it's been really good about this for a little while. I think TypeScript is really the the the key to it all, the fact that TypeScript is so smart about your code.
Wes Bos
Apparently, the Versus Code language server for Deno will respect your import map, which is good.
Wes Bos
So maybe that has something to do with the TypeScript language server again. So TypeScript doesn't know what import maps are.
Wes Bos
So again, hopefully it makes its way into Node, which hopefully means it will make its way into TypeScript, which hopefully means that It will be in in Versus Code eventually. So it's kind of early days. It's now in the browser. So hopefully we'll start to see in the next 6 months or so some stuff moving on all of this. Cool. Well, these are import maps.
Scott Tolinski
Wes, anything else that you have on import maps? I'm I'm really excited that this is is finally here. And keep in mind, it's it's in Safari technical preview. So with Safari, like, honestly, one of the biggest bummers about Safari is that you have to wait for the OS to update or the the user to update their their browser.
Scott Tolinski
But it's in the technical preview, so, you know, that that's good for us. That means that the next time anything gets updated, released for iOS and people actually update it on their phones, which for Apple. At least they actually do. Right? If you if you were to say this is tied to a version update in Windows, it would never get updated people hate updating their windows. But, users seem to update their Mac stuff fairly often. So, hopefully, that means we'll be able to reliably use this in some degree. And I don't know if I'll be rushing to use it, but it's nice to have the option. And it's nice that it exists, especially for for small little projects that you're going to hack together. Exactly. There. Also, I should also say there is a polyfill
Wes Bos
if you do want to use this in it. But honestly, the way I see it as This is probably just a really good thing for small projects, like you said, and it's a standard that we can now push into all of our tooling that will work Across the board. Sick.
Wes Bos
That's it. Thanks for tuning in. Catch you later. Peace. Peace.
Scott Tolinski
Head on over to syntax .fm for a full archive of all of our shows. And don't forget to subscribe in your podcast player or drop a review if you like this show.