2 posts on Web Architecture

External import maps, today!

4 min read Report broken page

A few weeks ago, I posted lamenting the current state of web dependencies. Turns out that external import maps — the lack of which I had identified as a core limitation — can be emulated today!

A few weeks ago, I posted Web dependencies are broken. Can we fix them?. Today’s post is a little less gloomy: Turns out that the major limitation that would allow centralized set-it-and-forget-it import map management can be lifted today, with excellent browser support!

The core idea is that you can use DOM methods to inject an import map dynamically, by literally creating an <script type="importmap"> element in a classic (blocking) script and appending it after the injector script. 💡

This is a gamechanger. It makes external import maps nice-to-have sugar instead of the only way to have centralized import map management decoupled from HTML generation.

All we need to do is build a little injector script, no need for tightly coupled workflows that take over everything. Once you have that, it takes a single line of HTML to include it anywhere. If you’re already using a templating system, great! You could add <script src="importmap.js"></script> to your <head> template for every page. But you don’t need a templating system: even if you’re rawdogging HTML (e.g. for a simple SPA), it’s no big deal to just include a <script src="importmap.js"></script> in there manually.

This is not even new: when the injector is a classic (non-module) script placed before any modules are fetched, it works in every import map implementation, all the way back to Chrome 89, Safari 16.4+, and Firefox 108+!

Turns out, JSPM made the same discovery: JSPM v4 uses the same technique. It is unclear why it took all of us so long to discover it but I’m glad we got there.

Continue reading


Web dependencies are broken. Can we fix them?

14 min read Report broken page

Dear JS ecosystem, I love you, but you have a dependency management problem when it comes to the Web, and the time has come for an intervention.

A cartoon where JS is shown hanging out drinking with bundlers. Webpack is saying “just one more config!” and Vite and Rollup are saying “We can optimize this!”. The event looks like it's winding down after hours of depravity. On the right side, a group of fed up developers are holding up an “Intervention” banner.
No, this is not another rant about npm’s security issues.

Abstraction is the cornerstone of modern software engineering. Reusing logic and building higher-level solutions from lower-level building blocks is what makes all the technological wonders around us possible. Imagine if every time anyone wrote a calculator they also had to reinvent floating-point arithmetic and string encoding!

And yet, the web platform has outsourced this fundamental functionality to third-party tooling. As a result, code reuse has become a balancing of tradeoffs that should not have existed in the first place.

In NodeJS, you just npm install and reference specifiers straight away in your code. Same in Python, with pip install. Same in Rust with cargo add. In healthy ecosystems you don’t ponder how or whether to use dependencies. The ecosystem assumes dependencies are normal, cheap, and first-class. You just install them, use them, and move on. “Dependency-free” is not a badge of honor.

Instead, dependency management in the web platform consists of bits and bobs of scattered primitives, with no coherent end-to-end solution. Naturally, bundlers such as Webpack, rollup, and esbuild have picked up the slack, with browserify being the one that started it all, in 2012.

Continue reading