Import specifier stacks, for fallback specifiers

I mentioned this in passing in my Weak imports proposal, but a couple days ago I was reminded of how useful this could be in regular imports too, when unpkg was down and suddenly several of my Vue apps were not working.

Import specifier stacks would be a comma-separated list of import specifiers. If the first specifier fails to resolve for whatever reason, the second one will be attempted and so on.

Example:

import * as Vue from "https://unpkg.com/vue@3/dist/vue.esm-browser.js", 
                     "https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.js";

One could even combine bare specifiers and URLs:

import * as Vue from "vue", "https://unpkg.com/vue@3/dist/vue.esm-browser.js";

This would load Vue from a CDN if there is no import map that makes a bare vue resolve to something useful (in a browser) or if it's not installed locally (in a build environment).

Another pattern:

import * as Vue from "./vue.js", "https://unpkg.com/vue@3/dist/vue.esm-browser.js";

This would load Vue from a CDN if there is no vue.js file adjacent to the current file.

Note that comma-separating multiple import specifiers is currently a syntax error, so this should not introduce any web compat issues.

There are several ways to introduce this functionality to dynamic imports.
We cannot allow import() to take multiple specifiers, as the second argument is currrently reserved for metadata. Another option could be to allow the first parameter to be an array of specifiers, but this is not backwards compatible. Introducing a fallbacks property in the second argument seems to be backwards compatible with current implementations and would just load the first URL if the runtime doesn't support specifier stacks:

let Vue = await import("https://unpkg.com/vue@3/dist/vue.esm-browser.js", {
	fallbacks: ["https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.js"]
});
2 Likes

An earlier version of the import maps proposal had this fallback feature. I can't find a reference for when it was dropped. Maybe @domenic would be able to point you to the rationale. But I'm assuming they are still open to including this feature in import maps, as my understanding is that most of the dropped functionality was only dropped to make the MVP easier. I think you should explore that route first, and if that fails for some reason, we can look into it in TC39.

1 Like

I am dealing with similar problem in microfrontend architecture:

Application assets:

  • app.js
  • library-v1.js

Library assets:

  • library-v2.js

I would like to deploy the library assets independently from the application. Whenever the library assets cannot be found (deploy new version), I would like to use the application's fallback asset.