ESM, meaning ES Modules, meaning JavaScript Modules. Like, import
and friends.
Browsers support it these days. There is plenty of nuance, but as long as you’ve dropped IE, the door is fairly open.
Before ESM, the situation for JavaScript projects was:
- We’ve got packages we need to use from npm.
- We’ll install them from npm ahead of time with our
package.json
,npm install
and whatnot. - We’ll write
import
statements that are invalid ESM for some reason (developer convenience, I guess) and assume we’re importing packages from a localnode_modules
folder. - Our bundler will know what to do with those invalid imports.
- This is all OK, because word on the street is that bundling is still required for performance, and it does other stuff we want anyway, like run Babel and friends.
Now that we can count on ESM more, the story is shifting somewhat, and all of those things are being questioned.
- What if we didn’t have to
npm install
? - What if we don’t need a bundler?
- What if performance is fine, between HTTP/2+, global CDNs, browsers doing fancy things, etc.?
- What if maybe we shouldn’t be compiling code so much because we’re down-compiling too much?
We’re seeing next-generation tooling that leans into all that. Snowpack 3 was just released and look at this:
That React (with JSX), being written just as it normally is, and there was no npm install
, no node_modules
directory, and no build step. But, still a dev server and reloading. So light. Very refreshing.
I just listened to a recent Toolsday episode where Una and Chris chatted with Jason Miller about WMR, which I hadn’t heard of until then. It feels very spiritually similar to Snowpack/Skypack. With WMR, you get to use npm packages without having to install them, or write with things like JSX, TypeScript or CSS Modules, and get a bunch of dev conveniences, like a server, hot reloading, etc.
Something is clearly in the water here, and I think that something is a leaning into ESM.
Even on the Node.js side, ESM is happening. Here’s Sindre Sorhus, who has over 1,000 npm packages(!):
At the end of April 2021, Node.js 10 will be end-of-life, which means that package maintainers can target Node.js 12. This Node.js version has full support for JavaScript Modules, also known as ESM.
He’s planning to move almost all of those 1,000 packages to ESM in 2021. Not a “dual” setup where you output multiple different formats… just ESM, and he’s encouraging everyone to do the same. I would think this momentum toward direct ESM usage in the browser builds heavily when the npm ecosystem is doing the exact same thing.
And when you do need to bundle because, say, something on npm isn’t yet ready for ESM, then next-gen bundlers are getting smoking fast.
Right now with npm, as long as I’ve already downloaded the packages, it doesn’t matter if I want to run my project without access to the internet. Will ESM cache locally somewhere other than the browser you’re developing in?
CDNs like Skypack that serve these packages will cache the package and hold the cache longer the more times it is hit. So very popular libraries would be extremely extremely fast on them. Or maybe I am wrong. Idk
You’re confusing two things I’m afraid.
Snowpack or WMR will cache those locally just like NPM/Yarn (maybe not shared with other projects though, I don’t know).
However, if you
import Foo from "https://…"
right in the browser without some tool to transform it, there’s no local caching involved.I think that’s maybe true for WMR, but Skypack is a global CDN for packages where you aren’t pulling locally at all, and Snowpack 3 has “streaming imports” that use it. From their blog post:
Wait aren’t the Node support ES modules also the fake ES modules?
Regarding your “What if maybe we shouldn’t be compiling code so much” question, and your very last paragraph, aren’t you somehow confusing bundling with transpiling and/or resolving dependencies?
There are reasons for bundling other than using Babel/Bublé/whatever or even importing using “bare import specifiers”, you can use Babel/etc. without bundling, and finally you could probably have a tool that rewrites bare import specifiers and move files around without touching anything else from your code (e.g. as a workaround for lack of import-maps support).
We tend to use bundlers for all of these things, but they are only steps in our build pipeline that we could do separately, or not at all.