WICG/import-maps

Issue with Browser Extensions

guybedford opened this issue ยท 16 comments

One issue came up recently with using import maps in production workflows is that browser extensions that inject ES modules into the page will block further import maps in the page from being processed with the error:

An import map is added after module script load was triggered.

As a result import maps are actually a risk to ship for production websites as users with extensions enabled can cause websites to break!

I think it would be worthwhile to find a way around this easy footgun that users and extension authors wouldn't necessarily be aware of.

The browser extension that injects ES modules is Apollo client devtools - https://github.com/apollographql/apollo-client-devtools.

Sure. It seems like easiest fix would be for such extensions to inject into the bottom of the page, instead of the top.

Hit this one today, I wonder if we could make user experience of it slightly better than extension hunting in this case?

To follow up here, despite the bug report being open a month, Apollo has not released a fix here so that import maps are still broken for all Apollo devtools extension users.

This one case indicates that extension authors might not be so quick to "inject into the bottom of the page instead of the top" and that this is a real issue affecting real usage.

Yeah, it definitely depends on whether extension authors consider this case important.

Apollo haven't shipped a fix. This keeps coming up - rails/importmap-rails#33.

dhh commented

Just adding my two cents that I think it's unrealistic that every browser extension out there in the wild is going to get cleaned up. And leaving it like this, where any browser extension injecting JS first, can silently break an app is going to make adoption of import maps difficult. Because users won't know what broke the app, and they'll write the maker, who then have to slowly debug the fact that it's caused by an extension. That invariably leads to "why are we doing this again?" questions from business.

I don't think that it will be easy to advocate for importmaps with this issue standing.
In practice this translates into-

  • Is it possible to stop extensions from injecting es modules on pages?
  • Is it possible to track down misbehaved extensions and file bug report?
  • Is it possible to consider this behaviour not as bug by extension author and not do anything about it?
  • Is it possible to not use importmaps?

Is there any current workaround for this? Specifically, in Rails 7 apps?

@thewoolleyman es-module-shims is designed to work around this by detecting when this happens and running the polyfill. If that is not applying for you please do post an issue to es-module-shims.

@guybedford Thanks for the reference. Simply including the shim as an async script didn't work to fix the issue with Apollo Client Devtools, but that can be a separate issue followup as you suggested.

Simply including the shim as an async script didn't work to fix the issue with Apollo Client Devtools, but that can be a separate issue followup as you suggested.

See follow up issue and reproduction of problem in a clean Rails 7 app here: guybedford/es-module-shims#267 (comment)

Faced the issue today with Chrome/Edge 103 on MacOS because of the <link rel"modulepreload" href="https://ga.jspm.io/npm:es-module-shims@1.5.1/dist/es-module-shims.js"> placed before the <script type="importmap">...</script>.

It was innocuous before, it is now considered as script...

Once I removed the statement, the blocking error disappeared.

Would it be possible instead for extensions to easily inject a module to after the importmap is loaded, and before the first module if there is no importmap defined?

A year later and this is still a problem for app developers moving to ES Modules. Is the expectation that browsers will not be fixing this and it is up to all extension developers to not break websites?

Another use case I would like to share where dynamically injecting or adjusting import maps would be really helpful:

Imagine a browser playground/IDE, someone is typing import foo from 'bar';, and I'd like the playground to automatically search up the dependency (e.g. a CDN), create an import map entry for it and inject it into the playground environment, making the bare import work "on the fly".

I totally agree with @dhh , my issue is only secondary to this bigger issue of third party stuff (e.g. extensions) breaking apps using importmaps. Really hard to advocate for importmaps when there's serious reliability issues with it.

This issue manifests itself not only with browser extensions but in various scenarios where code from different places is integrated into a single page. At Shopify we've seen breakage when we moved certain scripts to type=module, due to the fact that some theme developers integrated import maps below those scripts.

It seems like it'd be significantly less fragile to enable an import map after module scripts were resolved, and only have that map apply to future module script resolution. It might be interesting to also enable multiple import maps while we're at it, to reduce fragility even further.