Closing the SRI gap for ES modules

Shopify’s checkout is a managed service built to meet PCI v4 DSS compliance. A core requirement there is controlling exactly which scripts load and execute during checkout, so their contents can’t be tampered with. Subresource Integrity (SRI) is the web platform mechanism designed for that: it checks integrity hashes on downloaded resources and blocks execution on mismatch, keeping resources consistent from build time to delivery.

But SRI only covered top-level scripts, styles, and preloads. It had no support for imported JavaScript modules. That forced Shopify to shim dynamic script imports instead of using the platform’s own import() function, creating maintenance burden and runtime overhead.

Bringing integrity to import maps

The fix builds on an existing proposal by Guy Bedford to fold integrity metadata into import maps. Rather than inventing a new mechanism, the approach uses import maps to associate module URLs with their integrity hashes. That avoids reintroducing the cache-invalidation cascades import maps were designed to prevent.

With that in place, code like import("./module/shapes/square.js") works unchanged, with the module’s integrity verified against the declared hash before execution.

The import map specification and its Chromium implementation were in good shape, with the code tracking the spec closely. Two existing sections in import maps gave confidence that integrity could land as a third. A rough Chromium prototype, spec draft, and initial test suite came together on a single flight—no in-seat power required. Spec and Chromium owners quickly indicated the design should also handle static imports, top-level module scripts, and modulepreload. Full iteration ran 32 commits for Chromium and 21 for the HTML spec PR.

Two engines, one feature

An intent to prototype went out only after implementation began. Requests for position followed to WebKit, Mozilla, and the TAG. Feedback was positive, and WebKit’s stance encouraged a Safari implementation as well. That meant extra work: script-loading internals differ substantially between engines, particularly for static imports.

With two implementations in place and a successful WHATWG review, the HTML spec PR landed and Chromium’s intent to ship was approved. The feature shipped in Chromium 127, reaching stable channels in Chrome and Edge. It’s also in Safari 18 Beta, expected to hit stable in the following months.

What made this one move fast

Having a concrete proposal already on the table changed the dynamics. Cross-browser feature requests without an implementation plan tend to stall; the existing design work here made a difference at every stage.

The overall timeline was roughly seven weeks from start to finish, with about two weeks of full-time effort. That’s a reminder that small, well-defined, uncontroversial additions can move through the web platform quickly.

There’s also a broader point: you don’t have to work for a browser vendor to contribute browser implementations. Shipping this feature into multiple rendering engines as part of a Shopify role unlocked a missing primitive for the platform, and the result improves commerce and the web at large.