Skip to content

The v1 API

The mport 1.x API (published as the unscoped mport, last version 1.0.0), kept with the same signatures as a thin layer over the router.

mport<T>(input: string | { name, version?, path? }, importOptions?: ImportCallOptions): Promise<T>

The default export: MPort() with the default origins. Resolves to the module.

MPort(options?: { cdns?, useCache?, cacheKey? }): (input, importOptions?) => Promise<module>
MPort(...origins: string[]): (input, importOptions?) => Promise<module>
MPortURL(options?): (input, importOptions?) => Promise<[module, url, info]>
MPortURL(...origins: string[]): (input, importOptions?) => Promise<[module, url, info]>
Option Type Default Meaning
cdns Array<string | { path, versionMarker?, defaultVersion? }> DEFAULT_ORIGINS origins to race; strings are { path }; an empty array means the default
useCache "localhost" none remember each winning URL in localStorage and reuse it
cacheKey string "mport-cache" the localStorage key (one JSON object of input → URL)

Passing only strings (MPort("a.cdn/", "b.cdn/")) is the same as { cdns: [...] }. importOptions is passed to import(url, importOptions) (the Firefox entry ignores it).

Input: "name@version/path" or { name, version, path }. With no version, v1 uses latest (it does not resolve ranges; the CDN does). Scoped names work.

With a path, each call builds a router over the origins, race(...origins.map(origin)) with probe: "import", resolveVersions: false and a circuit breaker that never opens, and resolves: every origin’s URL is imported at once and the first import to succeed wins. info is that Resolution without module (url, provider (the origin path), version, trace, …). If every import fails it rejects with a RoutingError.

Without a path, it races <origin>/<name>@<version>/package.json from every origin (JSON import in the standard entry, fetch in the Firefox entry), takes the first that loads, picks its entry with entryOf() (so exports → module → main, preferring ESM), and imports that one URL from the same origin. info is { url, name, version, packageJson, entry, cached: false } with no trace. If no package.json loads it rejects with AggregateError("mport: could not load <name>"); if the entry import fails, that error is the rejection (there is no failover for the entry).

useCache: "localhost": before racing, a stored URL for the same input is used if it starts with https:// plus one of the current origins’ paths. Then the call imports it directly and info is { url, cached: true, trace: [] }; if that import fails, the call rejects rather than racing again. Storage errors are ignored.

@johnhenry/mport/firefox exports the same names. Its importer is the one-argument import(url) (so importOptions is ignored), it reads package.json with fetch (rejecting with mport: <url> responded <status> on a non-OK response), and no module it loads contains a two-argument import(), which older SpiderMonkey rejects at parse time. test/v1.test.mjs walks its import graph to keep it that way.

Nothing that 1.x exported has been removed. Behaviour changes, all bug fixes, plus one addition:

1.x Now
Promise.race: one CDN that failed quickly rejected the whole import the first success wins
"@scope/[email protected]/x.js" split on the first @ scoped names parse
MPort("a.cdn/", "b.cdn/") ignored its arguments the origins are used
useCache: "localhost" compared a URL host with an origin path and never matched it stores and reuses the winner
mport/firefox referenced undefined variables it works
path-less imports used main exports → module → main, preferring ESM; this can change which file loads for packages whose main is CommonJS
MPortURL resolved to [module, url] [module, url, info]; two-element destructuring is unaffected
the 1.0.0 tarball lacked config.mjs and race-which.mjs the package ships all of src/
the package was mport it is @johnhenry/mport, restarting at 0.0.0; the router API (createRouter and everything above) is new

The default race still mixes builds (raw jsDelivr/unpkg files against jspm’s transformed output), because that is what 1.x did. For consistent builds use a router, e.g. createRouter({ "*": race(jsDelivr(), unpkg()) }).

Export Value
DEFAULT_ORIGINS ["cdn.jsdelivr.net/npm/", "ga.jspm.io/npm:", "unpkg.com/"], the v1 race
DEFAULT_CACHE_KEY "mport-cache", the v1 localStorage key