require(). You had to be intimately familiar with
this and lexical
scoping, otherwise it’d come back to bite you. All JS having global scope (even vendor scripts) was
programming communities for the things it lacked compared to more mature languages, chiefly of all,
a module system.
So why didn’t more people notice?
🔗the land of make-believe
In preparing for a talk I gave last year, I realized just how much JS has changed over the last decade. Node.js was released in 2010 with the CommonJS module system, and as a result, npm. That’s over 10 years of CommonJS we’ve been writing, and we’re not slowing down there (if this is all mumbo-jumbo to you, hopefully my talk will help).
In the land of Node, we got Gulp, Grunt, Babel, webpack, Browserify, and Rollup. These are all tools that fundamentally changed how we wrote JS. And they all, in their own unique ways, compensated for JS’ lack of a module system. Gulp and Grunt gave you more tools to invent your own bundle, whereas Browserify and webpack embraced the idea of a JS module system by completely simulating it, and abstracting it away from you. Babel made everything possible.
But the point is: all of these tools over the past 10 years created a land of make-believe that JS itself (or browsers) didn’t support. This wasn’t a bad thing, as it let us code more, faster, and we got to stress-test the future before actually arriving—all good things.
But now we don’t need it anymore, and it’s hard to change everything and start over again. And perhaps that fear of starting over—again—has kept us from recognizing the exciting new future. Yet we must move forward.
🔗why switch to ESM
So, why switch to ESM? What do we stand to gain by changing everything?
This is huge. We can import any module from anywhere on the internet, and are no longer bound to npm. Consider Deno, a new V8/Rust/Tokio runtime that might replace Node.js. This is a line from the docs:
Comparison to Node.js
Deno does not use
This single, understated line is a huge shift. How can you just… move away from the most popular
package repository in history? Well thanks to ESM, you can load modules from any URL, whether that
be locally, or a CDN.
npm install is now no longer needed; the language itself supports
🔗no bundling or transpilation needed
Imagine a world where you don’t need to run any CLI command whatsoever to start a front-end application. No runtime, webpack, build times… nothing.
To learn more about this, check out A future without webpack.
In the webpack world before ESM, you had to make trade-offs: rolling everything into one giant bundle meant no load times after initializing, but that initial download is brutal. Conversely, “code splitting” into tiny chunks made each chunk easily-downloadable but code is almost certainly duplicated across those chunks and a user will be paying for the same weight over and over again (🤔 not entirely unlike buying a home with cash or paying it off over 30 years, now that I think about it).
With ESM, the entire dependency tree is exposed to the browser, so the browser can perfectly cache what it needs, and nothing more (imagine if you paid nothing on your home to start, zero interest ever, and you only paid for the parts of the home you used, as you used them). Of course, cache invalidation is a separate problem that will be with us until the end of time. But that aside, ESM truly is the perfect caching story for JS.
🔗making the switch
So let’s say you’re sold on ESM… how do you make the leap? Well, it may be your tools that are to blame:
- React: doesn’t ship an ESM-ready package (as of Mar 2020)
< 8%of npm packages ship ESM (as of Oct 2019)
- Node.js: though it supports ESM, it’s not in a stable LTS release yet (as of Nov 2019)
- webpack: can’t ship your code as ESM, nor can it take advantage of ESM features like remote imports.
By choosing these tools even in new projects, you’re shipping legacy code that already has a limited lifespan. But some of that isn’t within your control, sure—maybe your company, or client demands these. Or you just can’t accomplish what you need to with alternatives; that’s understandable.
But there are also some new, exciting projects on the horizon that are shaping up to replace now-legacy CommonJS tools:
Snowpack (a play on ”no pack”) is an install tool (disclosure: that I’m one of the lead
contributers for) that lets you ship ESM-ready code straight to the browser
and use npm. You can
npm install like normal, and lets you use Preact, Vue, Svelte, and more
but with zero build time and no configuration.
Pika Registry does all the work of finding ESM-ready packages for you. Search for any keyword like you would on npm, except Pika Registry can tell you instantly whether or not that package supports ESM.
Deno is a new competitor to Node.js, built with V8, Rust, and Tokio and features native TypeScript and ESM support out-of-the-box. Its guiding principle is to more closely mirror ECMAScript in the areas where Node departed, principally only allowing ESM rather than CommonJS. Though the project is in beta, it’s already gathering community attention and shows tons of promise.
To recap, the current state of ESM in 2020 is: it’s ready to use everywhere, but it’s up to you to opt-in! Give some of the new ESM tools a try, and you might find yourself dealing with less tooling, less configuration, and other great benefits while helping the community at large unify around ESM.