@remix-run/multiple-import-maps-polyfill 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -0
- package/README.md +105 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/core.d.ts +6 -0
- package/dist/lib/core.d.ts.map +1 -0
- package/dist/lib/core.js +470 -0
- package/dist/lib/env.d.ts +12 -0
- package/dist/lib/env.d.ts.map +1 -0
- package/dist/lib/env.js +33 -0
- package/dist/lib/features.d.ts +4 -0
- package/dist/lib/features.d.ts.map +1 -0
- package/dist/lib/features.js +70 -0
- package/dist/lib/native-resolve.d.ts +2 -0
- package/dist/lib/native-resolve.d.ts.map +1 -0
- package/dist/lib/native-resolve.js +59 -0
- package/dist/lib/polyfill.d.ts +41 -0
- package/dist/lib/polyfill.d.ts.map +1 -0
- package/dist/lib/polyfill.js +77 -0
- package/dist/lib/resolve.d.ts +16 -0
- package/dist/lib/resolve.d.ts.map +1 -0
- package/dist/lib/resolve.js +167 -0
- package/dist/lib/self.d.ts +3 -0
- package/dist/lib/self.d.ts.map +1 -0
- package/dist/lib/self.js +2 -0
- package/dist/lib/trusted-types.d.ts +15 -0
- package/dist/lib/trusted-types.d.ts.map +1 -0
- package/dist/lib/trusted-types.js +21 -0
- package/package.json +44 -5
- package/src/index.ts +6 -0
- package/src/lib/core.ts +616 -0
- package/src/lib/env.ts +37 -0
- package/src/lib/features.ts +80 -0
- package/src/lib/native-resolve.ts +69 -0
- package/src/lib/polyfill.ts +89 -0
- package/src/lib/resolve.ts +225 -0
- package/src/lib/self.ts +2 -0
- package/src/lib/trusted-types.ts +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Remix Software Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
Portions of this software are derived from ES Module Shims:
|
|
24
|
+
|
|
25
|
+
Copyright (C) 2018-2025 Guy Bedford
|
|
26
|
+
|
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
28
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
29
|
+
in the Software without restriction, including without limitation the rights
|
|
30
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
31
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
32
|
+
furnished to do so, subject to the following conditions:
|
|
33
|
+
|
|
34
|
+
The above copyright notice and this permission notice shall be included in all
|
|
35
|
+
copies or substantial portions of the Software.
|
|
36
|
+
|
|
37
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
38
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
39
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
40
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
41
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
42
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
43
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,107 @@
|
|
|
1
1
|
# multiple-import-maps-polyfill
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Polyfill for dynamic JavaScript imports that depend on import maps added after the document's initial import map. Browsers with native support for multiple import maps continue to use native dynamic imports.
|
|
4
|
+
|
|
5
|
+
The module loading logic in this package was adapted from [ES Module Shims](https://github.com/guybedford/es-module-shims) by Guy Bedford.
|
|
6
|
+
|
|
7
|
+
This package assumes the initial document contains one complete import map before any module scripts. It is designed to load dynamic imports that depend on additional import maps installed after the initial page load.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Detects native support for multiple import maps
|
|
12
|
+
- Loads dynamic imports through every import map in the document when a polyfill is required
|
|
13
|
+
- Preloads dynamic modules through the same polyfill cache
|
|
14
|
+
- Resolves native module types through import maps while leaving their loading semantics to the browser
|
|
15
|
+
- Supports import-map integrity metadata
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm i remix
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Use `importModule` in place of `import()` when a dynamic import may depend on an import map added at runtime:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { importModule } from 'remix/multiple-import-maps-polyfill'
|
|
29
|
+
|
|
30
|
+
let moduleUrl = new URL('./features/search.ts', import.meta.url).href
|
|
31
|
+
let feature = await importModule(moduleUrl)
|
|
32
|
+
feature.openSearch()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`importModule` uses native `import()` when the browser supports multiple import maps. In other browsers, it loads the module through the polyfill using every import map currently installed in the document.
|
|
36
|
+
|
|
37
|
+
Use `detectMultipleImportMapSupport` and `preloadShim` when an integration also manages module preloads. For example, configure Remix UI to load client entries discovered during navigation:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import {
|
|
41
|
+
detectMultipleImportMapSupport,
|
|
42
|
+
importModule,
|
|
43
|
+
preloadShim,
|
|
44
|
+
} from 'remix/multiple-import-maps-polyfill'
|
|
45
|
+
import { run } from 'remix/ui'
|
|
46
|
+
|
|
47
|
+
run({
|
|
48
|
+
async loadModule(moduleUrl, exportName) {
|
|
49
|
+
let module = await importModule(moduleUrl)
|
|
50
|
+
let Component = module[exportName]
|
|
51
|
+
if (typeof Component !== 'function') {
|
|
52
|
+
throw new Error(`Unknown component: ${moduleUrl}#${exportName}`)
|
|
53
|
+
}
|
|
54
|
+
return Component
|
|
55
|
+
},
|
|
56
|
+
async processClientEntryPreloads(preloads) {
|
|
57
|
+
if (await detectMultipleImportMapSupport()) return preloads
|
|
58
|
+
|
|
59
|
+
preloadShim(preloads)
|
|
60
|
+
return []
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Browsers with multiple import map support retain native module loading and native `<link rel="modulepreload">` elements. Other browsers load late client entries and preloads through the polyfill.
|
|
66
|
+
|
|
67
|
+
`detectMultipleImportMapSupport()` returns a cached promise. When it detects that the polyfill is required, it begins loading the polyfill runtime in the background so the work can overlap with a later `importShim()` or `preloadShim()` call. Browsers with multiple import map support do not load the polyfill runtime.
|
|
68
|
+
|
|
69
|
+
`importShim()` always uses the polyfill to load a dynamic JavaScript import using every import map currently installed in the document. It does not detect native support. `preloadShim()` always uses the polyfill fetch cache rather than native module preload links. Like native module preloads, it fetches only the supplied module specifier or array of specifiers and caches their responses for later imports. Preload failures are ignored. `importShim()` reports the failure if the module is later required.
|
|
70
|
+
|
|
71
|
+
## Content Security Policy
|
|
72
|
+
|
|
73
|
+
Polyfilled module graphs are evaluated from blob URLs, and `es-module-lexer` compiles its parser from Wasm. Content Security Policies must allow `blob:` module scripts and Wasm compilation with `'wasm-unsafe-eval'`.
|
|
74
|
+
|
|
75
|
+
The support detector creates a Trusted Types policy named `remix/multiple-import-maps-polyfill`. Allow this policy when Trusted Types are required for scripts, for example:
|
|
76
|
+
|
|
77
|
+
```http
|
|
78
|
+
Content-Security-Policy: script-src 'self' blob: 'wasm-unsafe-eval'; require-trusted-types-for 'script'; trusted-types remix/multiple-import-maps-polyfill;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## `remix/assets` HMR Support
|
|
82
|
+
|
|
83
|
+
HMR appends mappings for updated modules to the document in additional `<script type="importmap">` elements. Configure the Remix asset server's `hmr.moduleImporter` option to use the polyfilled `importModule` function when these updates must work in browsers without native support for multiple import maps:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { createAssetServer } from 'remix/assets'
|
|
87
|
+
import { createBrowserHmrChannel } from 'remix/node-hmr/runtime'
|
|
88
|
+
|
|
89
|
+
let assets = createAssetServer({
|
|
90
|
+
hmr: {
|
|
91
|
+
channel: createBrowserHmrChannel,
|
|
92
|
+
moduleImporter: 'remix/multiple-import-maps-polyfill',
|
|
93
|
+
},
|
|
94
|
+
watch: true,
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The module importer and its dependencies must be available through the document's initial import map. Importing `remix/multiple-import-maps-polyfill` from the application's main client entry satisfies this requirement.
|
|
99
|
+
|
|
100
|
+
## Related Packages
|
|
101
|
+
|
|
102
|
+
- [`assets`](https://github.com/remix-run/remix/tree/main/packages/assets) - Compiles and serves browser assets
|
|
103
|
+
- [`ui`](https://github.com/remix-run/remix/tree/main/packages/ui) - Loads client entries discovered during navigation
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
See [LICENSE](https://github.com/remix-run/remix/blob/main/packages/multiple-import-maps-polyfill/LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { detectMultipleImportMapSupport, importModule, importShim, preloadShim, } from './lib/polyfill.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type ModuleNamespace = Record<string, unknown>;
|
|
2
|
+
export declare function importShim(id: string, opts?: string | ImportCallOptions, parentUrl?: string): Promise<ModuleNamespace>;
|
|
3
|
+
export declare function preloadShim(ids: string | readonly string[], parentUrl?: string): Promise<void>;
|
|
4
|
+
export declare const registerNativeModule: (url: string) => void;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/lib/core.ts"],"names":[],"mappings":"AA6BA,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AA2E9C,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE,MAAM,GAAG,iBAAiB,EACjC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAU1B;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAC/B,SAAS,SAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CASf;AAcD,eAAO,MAAM,oBAAoB,QAAS,MAAM,KAAG,IAElD,CAAA"}
|
package/dist/lib/core.js
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { resolveAndComposeImportMap, resolveImportMap, resolveIfNotPlainOrUrl, asURL, } from './resolve.js';
|
|
10
|
+
import { baseUrl as pageBaseUrl, dynamicImport, createBlob, throwError, fromParent, hasDocument, defaultFetchOpts, } from './env.js';
|
|
11
|
+
import { featureDetectionPromise, supportsImportMaps, supportsMultipleImportMaps, } from './features.js';
|
|
12
|
+
import * as lexer from 'es-module-lexer';
|
|
13
|
+
// This source is adapted from ES Module Shims 2.8.4.
|
|
14
|
+
const bridgeName = `remix.importMapPolyfill.runtime:${import.meta.url}`;
|
|
15
|
+
const bridgeKey = Symbol.for(bridgeName);
|
|
16
|
+
const bridgeExpression = `globalThis[Symbol.for(${JSON.stringify(bridgeName)})]`;
|
|
17
|
+
const resolve = (id, parentUrl = pageBaseUrl) => {
|
|
18
|
+
let urlResolved = resolveIfNotPlainOrUrl(id, parentUrl) || asURL(id);
|
|
19
|
+
let firstResolved = firstImportMap && resolveImportMap(firstImportMap, urlResolved || id, parentUrl);
|
|
20
|
+
let composedResolved = composedImportMap === firstImportMap
|
|
21
|
+
? firstResolved
|
|
22
|
+
: resolveImportMap(composedImportMap, urlResolved || id, parentUrl);
|
|
23
|
+
let resolved = composedResolved || firstResolved || throwUnresolved(id, parentUrl);
|
|
24
|
+
// needsShim, shouldShim per load record to set on parent
|
|
25
|
+
let n = false, N = false;
|
|
26
|
+
if (!supportsMultipleImportMaps) {
|
|
27
|
+
// bare specifier and not resolved by first import map -> needs shim
|
|
28
|
+
if (!urlResolved && !firstResolved)
|
|
29
|
+
n = true;
|
|
30
|
+
// resolution doesn't match first import map -> should shim
|
|
31
|
+
if (firstResolved && resolved !== firstResolved)
|
|
32
|
+
N = true;
|
|
33
|
+
}
|
|
34
|
+
return { r: resolved, n, N };
|
|
35
|
+
};
|
|
36
|
+
// import()
|
|
37
|
+
export async function importShim(id, opts, parentUrl) {
|
|
38
|
+
if (typeof opts === 'string') {
|
|
39
|
+
parentUrl = opts;
|
|
40
|
+
opts = undefined;
|
|
41
|
+
}
|
|
42
|
+
let sourceType = opts?.with?.type;
|
|
43
|
+
await initPromise;
|
|
44
|
+
processImportMaps();
|
|
45
|
+
legacyAcceptingImportMaps = false;
|
|
46
|
+
return topLevelLoad(id, parentUrl || pageBaseUrl, defaultFetchOpts, undefined, sourceType);
|
|
47
|
+
}
|
|
48
|
+
export async function preloadShim(ids, parentUrl = pageBaseUrl) {
|
|
49
|
+
await initPromise;
|
|
50
|
+
processImportMaps();
|
|
51
|
+
await importMapPromise;
|
|
52
|
+
await Promise.allSettled((typeof ids === 'string' ? [ids] : ids).map((id) => processPreload(resolve(id, parentUrl).r, defaultFetchOpts)));
|
|
53
|
+
}
|
|
54
|
+
const throwUnresolved = (id, parentUrl) => {
|
|
55
|
+
throw Error(`Unable to resolve specifier '${id}'${fromParent(parentUrl)}`);
|
|
56
|
+
};
|
|
57
|
+
const metaResolve = function (id, parentUrl = this.url) {
|
|
58
|
+
return resolve(id, `${parentUrl}`).r;
|
|
59
|
+
};
|
|
60
|
+
const registry = {};
|
|
61
|
+
const nativeModules = new Set();
|
|
62
|
+
Reflect.set(globalThis, bridgeKey, Object.freeze({ importShim, registry }));
|
|
63
|
+
export const registerNativeModule = (url) => {
|
|
64
|
+
nativeModules.add(url);
|
|
65
|
+
};
|
|
66
|
+
const loadAll = async (load, seen) => {
|
|
67
|
+
seen[load.u] = 1;
|
|
68
|
+
await load.L;
|
|
69
|
+
await Promise.all(load.d.map(({ l: dep, s: sourcePhase }) => {
|
|
70
|
+
if (dep.b || seen[dep.u])
|
|
71
|
+
return;
|
|
72
|
+
if (sourcePhase)
|
|
73
|
+
return dep.f;
|
|
74
|
+
return loadAll(dep, seen);
|
|
75
|
+
}));
|
|
76
|
+
};
|
|
77
|
+
let firstImportMap = null;
|
|
78
|
+
// To support polyfilling multiple import maps, we separately track the composed import map from the first import map
|
|
79
|
+
let composedImportMap = { imports: {}, scopes: {}, integrity: {} };
|
|
80
|
+
const initPromise = Promise.all([lexer.init, featureDetectionPromise]).then(() => {
|
|
81
|
+
if (!hasDocument || !supportsImportMaps)
|
|
82
|
+
throw new TypeError('The multiple import map polyfill requires native import map support.');
|
|
83
|
+
attachMutationObserver();
|
|
84
|
+
});
|
|
85
|
+
const attachMutationObserver = () => {
|
|
86
|
+
let observer = new MutationObserver((mutations) => {
|
|
87
|
+
for (let mutation of mutations) {
|
|
88
|
+
if (mutation.type !== 'childList')
|
|
89
|
+
continue;
|
|
90
|
+
for (let node of mutation.addedNodes) {
|
|
91
|
+
if (node.tagName === 'SCRIPT') {
|
|
92
|
+
let script = node;
|
|
93
|
+
if (script.type === 'importmap')
|
|
94
|
+
processImportMap(script);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
observer.observe(document, { childList: true });
|
|
100
|
+
observer.observe(document.head, { childList: true });
|
|
101
|
+
processImportMaps();
|
|
102
|
+
};
|
|
103
|
+
let importMapPromise = initPromise;
|
|
104
|
+
let legacyAcceptingImportMaps = true;
|
|
105
|
+
async function topLevelLoad(url, parentUrl, fetchOpts, source, sourceType) {
|
|
106
|
+
await initPromise;
|
|
107
|
+
await importMapPromise;
|
|
108
|
+
url = (await resolve(url, parentUrl)).r;
|
|
109
|
+
// we mock import('./x.css', { with: { type: 'css' }}) support via an inline static reexport
|
|
110
|
+
// because we can't syntactically pass through to dynamic import with a second argument
|
|
111
|
+
if (sourceType === 'css' || sourceType === 'json') {
|
|
112
|
+
// Direct reexport for hot reloading skipped due to Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1965620
|
|
113
|
+
source = `import m from'${url}'with{type:"${sourceType}"};export default m;`;
|
|
114
|
+
url += '?entry';
|
|
115
|
+
}
|
|
116
|
+
let load = getOrCreateLoad(url, fetchOpts, undefined, source);
|
|
117
|
+
if (source)
|
|
118
|
+
load.N = true;
|
|
119
|
+
linkLoad(load, fetchOpts);
|
|
120
|
+
let seen = {};
|
|
121
|
+
await loadAll(load, seen);
|
|
122
|
+
resolveDeps(load, seen);
|
|
123
|
+
let module = await (load.n || load.N ? dynamicImport(load.b) : import(__rewriteRelativeImportExtension(load.u)));
|
|
124
|
+
// if the top-level load is a shell, run its update function
|
|
125
|
+
if (load.s)
|
|
126
|
+
(await dynamicImport(load.s)).u$_(module);
|
|
127
|
+
revokeObjectURLs(Object.keys(seen));
|
|
128
|
+
return module;
|
|
129
|
+
}
|
|
130
|
+
const revokeObjectURLs = (registryKeys) => {
|
|
131
|
+
let curIdx = 0;
|
|
132
|
+
let handler = globalThis.requestIdleCallback ||
|
|
133
|
+
globalThis.requestAnimationFrame ||
|
|
134
|
+
((fn) => setTimeout(fn, 0));
|
|
135
|
+
handler(cleanup);
|
|
136
|
+
function cleanup() {
|
|
137
|
+
for (let key of registryKeys.slice(curIdx, (curIdx += 100))) {
|
|
138
|
+
let load = registry[key];
|
|
139
|
+
if (load && load.b && load.b !== load.u)
|
|
140
|
+
URL.revokeObjectURL(load.b);
|
|
141
|
+
}
|
|
142
|
+
if (curIdx < registryKeys.length)
|
|
143
|
+
handler(cleanup);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const urlJsString = (url) => `'${url.replace(/'/g, "\\'")}'`;
|
|
147
|
+
let resolvedSource = '';
|
|
148
|
+
let lastIndex = 0;
|
|
149
|
+
const pushStringTo = (load, originalIndex, dynamicImportEndStack) => {
|
|
150
|
+
while (dynamicImportEndStack[dynamicImportEndStack.length - 1] < originalIndex) {
|
|
151
|
+
let dynamicImportEnd = dynamicImportEndStack.pop();
|
|
152
|
+
resolvedSource += `${load.S.slice(lastIndex, dynamicImportEnd)}, ${urlJsString(load.r)}`;
|
|
153
|
+
lastIndex = dynamicImportEnd;
|
|
154
|
+
}
|
|
155
|
+
resolvedSource += load.S.slice(lastIndex, originalIndex);
|
|
156
|
+
lastIndex = originalIndex;
|
|
157
|
+
};
|
|
158
|
+
const pushSourceURL = (load, commentPrefix, commentStart, dynamicImportEndStack) => {
|
|
159
|
+
let urlStart = commentStart + commentPrefix.length;
|
|
160
|
+
let commentEnd = load.S.indexOf('\n', urlStart);
|
|
161
|
+
let urlEnd = commentEnd !== -1 ? commentEnd : load.S.length;
|
|
162
|
+
let sourceUrl = load.S.slice(urlStart, urlEnd);
|
|
163
|
+
try {
|
|
164
|
+
sourceUrl = new URL(sourceUrl, load.r).href;
|
|
165
|
+
}
|
|
166
|
+
catch (e) { }
|
|
167
|
+
pushStringTo(load, urlStart, dynamicImportEndStack);
|
|
168
|
+
resolvedSource += sourceUrl;
|
|
169
|
+
lastIndex = urlEnd;
|
|
170
|
+
};
|
|
171
|
+
const resolveDeps = (load, seen) => {
|
|
172
|
+
if (load.b || !seen[load.u])
|
|
173
|
+
return;
|
|
174
|
+
seen[load.u] = 0;
|
|
175
|
+
for (let { l: dep, s: sourcePhase } of load.d) {
|
|
176
|
+
if (!sourcePhase && !dep.b) {
|
|
177
|
+
resolveDeps(dep, seen);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (!load.n)
|
|
181
|
+
load.n = load.d.some((dep) => dep.l.n);
|
|
182
|
+
if (!load.N)
|
|
183
|
+
load.N = load.d.some((dep) => dep.l.N);
|
|
184
|
+
// use native loader whenever possible (n = needs shim) via executable subgraph passthrough
|
|
185
|
+
// so long as the module doesn't use dynamic import or unsupported URL mappings (N = should shim)
|
|
186
|
+
if (!load.n && !load.N) {
|
|
187
|
+
load.b = load.u;
|
|
188
|
+
load.S = undefined;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
let [imports, exports] = load.a;
|
|
192
|
+
// "execution"
|
|
193
|
+
let source = load.S, depIndex = 0, dynamicImportEndStack = [];
|
|
194
|
+
// once all deps have loaded we can inline the dependency resolution blobs
|
|
195
|
+
// and define this blob
|
|
196
|
+
resolvedSource = '';
|
|
197
|
+
lastIndex = 0;
|
|
198
|
+
for (let { s: start, e: end, ss: statementStart, se: statementEnd, d: dynamicImportIndex, t, a, } of imports) {
|
|
199
|
+
// source phase
|
|
200
|
+
if (t === 4) {
|
|
201
|
+
let { l: depLoad } = load.d[depIndex++];
|
|
202
|
+
pushStringTo(load, start - 1, dynamicImportEndStack);
|
|
203
|
+
resolvedSource += `/*${source.slice(start - 1, end + 1)}*/'${depLoad.b}'`;
|
|
204
|
+
lastIndex = end + 1;
|
|
205
|
+
}
|
|
206
|
+
else if (t === 5 || t === 6) {
|
|
207
|
+
throw new TypeError('Dynamic source imports and import defer are not supported.');
|
|
208
|
+
}
|
|
209
|
+
// dependency source replacements
|
|
210
|
+
else if (dynamicImportIndex === -1) {
|
|
211
|
+
let keepAssertion = a > 0;
|
|
212
|
+
let { l: depLoad } = load.d[depIndex++], blobUrl = depLoad.b, cycleShell = !blobUrl;
|
|
213
|
+
if (cycleShell) {
|
|
214
|
+
let cycleLoad = depLoad;
|
|
215
|
+
// circular shell creation
|
|
216
|
+
if (!(blobUrl = cycleLoad.s)) {
|
|
217
|
+
blobUrl = cycleLoad.s = createBlob(`export function u$_(m){${cycleLoad.a[1]
|
|
218
|
+
.map(({ s, e }, i) => {
|
|
219
|
+
let depSource = cycleLoad.S;
|
|
220
|
+
let q = depSource[s] === '"' || depSource[s] === "'";
|
|
221
|
+
return `e$_${i}=m${q ? `[` : '.'}${depSource.slice(s, e)}${q ? `]` : ''}`;
|
|
222
|
+
})
|
|
223
|
+
.join(',')}}${cycleLoad.a[1].length
|
|
224
|
+
? `let ${cycleLoad.a[1].map((_, i) => `e$_${i}`).join(',')};`
|
|
225
|
+
: ''}export {${cycleLoad.a[1]
|
|
226
|
+
.map(({ s, e }, i) => `e$_${i} as ${cycleLoad.S.slice(s, e)}`)
|
|
227
|
+
.join(',')}}\n//# sourceURL=${cycleLoad.r}?cycle`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
pushStringTo(load, start - 1, dynamicImportEndStack);
|
|
231
|
+
resolvedSource += `/*${source.slice(start - 1, end + 1)}*/'${blobUrl}'`;
|
|
232
|
+
// circular shell execution
|
|
233
|
+
if (!cycleShell && depLoad.s) {
|
|
234
|
+
resolvedSource += `;import*as m$_${depIndex} from'${depLoad.b}';import{u$_ as u$_${depIndex}}from'${depLoad.s}';u$_${depIndex}(m$_${depIndex})`;
|
|
235
|
+
depLoad.s = undefined;
|
|
236
|
+
}
|
|
237
|
+
lastIndex = keepAssertion ? end + 1 : statementEnd;
|
|
238
|
+
}
|
|
239
|
+
// import.meta
|
|
240
|
+
else if (dynamicImportIndex === -2) {
|
|
241
|
+
load.m = { url: load.r, resolve: metaResolve };
|
|
242
|
+
pushStringTo(load, start, dynamicImportEndStack);
|
|
243
|
+
resolvedSource += `${bridgeExpression}.registry[${urlJsString(load.u)}].m`;
|
|
244
|
+
lastIndex = statementEnd;
|
|
245
|
+
}
|
|
246
|
+
// dynamic import
|
|
247
|
+
else {
|
|
248
|
+
pushStringTo(load, statementStart, dynamicImportEndStack);
|
|
249
|
+
resolvedSource += `${bridgeExpression}.importShim(`;
|
|
250
|
+
dynamicImportEndStack.push(statementEnd - 1);
|
|
251
|
+
lastIndex = start;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// support progressive cycle binding updates (try statement avoids tdz errors)
|
|
255
|
+
if (load.s && (imports.length === 0 || imports[imports.length - 1].d === -1))
|
|
256
|
+
resolvedSource += `\n;import{u$_}from'${load.s}';try{u$_({${exports
|
|
257
|
+
.filter((e) => e.ln)
|
|
258
|
+
.map(({ s, e, ln }) => `${source.slice(s, e)}:${ln}`)
|
|
259
|
+
.join(',')}})}catch(_){};\n`;
|
|
260
|
+
let sourceURLCommentStart = source.lastIndexOf(sourceURLCommentPrefix);
|
|
261
|
+
let sourceMapURLCommentStart = source.lastIndexOf(sourceMapURLCommentPrefix);
|
|
262
|
+
// ignore sourceMap comments before already spliced code
|
|
263
|
+
if (sourceURLCommentStart < lastIndex)
|
|
264
|
+
sourceURLCommentStart = -1;
|
|
265
|
+
if (sourceMapURLCommentStart < lastIndex)
|
|
266
|
+
sourceMapURLCommentStart = -1;
|
|
267
|
+
// sourceURL first / only
|
|
268
|
+
if (sourceURLCommentStart !== -1 &&
|
|
269
|
+
(sourceMapURLCommentStart === -1 || sourceMapURLCommentStart > sourceURLCommentStart)) {
|
|
270
|
+
pushSourceURL(load, sourceURLCommentPrefix, sourceURLCommentStart, dynamicImportEndStack);
|
|
271
|
+
}
|
|
272
|
+
// sourceMappingURL
|
|
273
|
+
if (sourceMapURLCommentStart !== -1) {
|
|
274
|
+
pushSourceURL(load, sourceMapURLCommentPrefix, sourceMapURLCommentStart, dynamicImportEndStack);
|
|
275
|
+
// sourceURL last
|
|
276
|
+
if (sourceURLCommentStart !== -1 && sourceURLCommentStart > sourceMapURLCommentStart)
|
|
277
|
+
pushSourceURL(load, sourceURLCommentPrefix, sourceURLCommentStart, dynamicImportEndStack);
|
|
278
|
+
}
|
|
279
|
+
pushStringTo(load, source.length, dynamicImportEndStack);
|
|
280
|
+
if (sourceURLCommentStart === -1)
|
|
281
|
+
resolvedSource += sourceURLCommentPrefix + load.r;
|
|
282
|
+
load.b = createBlob(resolvedSource);
|
|
283
|
+
load.S = undefined;
|
|
284
|
+
resolvedSource = '';
|
|
285
|
+
};
|
|
286
|
+
const sourceURLCommentPrefix = '\n//# sourceURL=';
|
|
287
|
+
const sourceMapURLCommentPrefix = '\n//# sourceMappingURL=';
|
|
288
|
+
// restrict in-flight fetches to a pool of 100
|
|
289
|
+
const p = [];
|
|
290
|
+
let c = 0;
|
|
291
|
+
const pushFetchPool = () => {
|
|
292
|
+
if (++c > 100)
|
|
293
|
+
return new Promise((resolve) => p.push(resolve));
|
|
294
|
+
};
|
|
295
|
+
const popFetchPool = () => {
|
|
296
|
+
c--;
|
|
297
|
+
let next = p.shift();
|
|
298
|
+
if (next)
|
|
299
|
+
next();
|
|
300
|
+
};
|
|
301
|
+
const doFetch = async (url, fetchOpts, parent) => {
|
|
302
|
+
let res, poolQueue = pushFetchPool();
|
|
303
|
+
if (poolQueue)
|
|
304
|
+
await poolQueue;
|
|
305
|
+
try {
|
|
306
|
+
res = await fetch(url, fetchOpts);
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
let error = e;
|
|
310
|
+
error.message =
|
|
311
|
+
`Unable to fetch ${url}${fromParent(parent)} - see network log for details.\n` + error.message;
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
popFetchPool();
|
|
316
|
+
}
|
|
317
|
+
if (!res.ok) {
|
|
318
|
+
throw Object.assign(new TypeError(`${res.status} ${res.statusText} ${res.url}${fromParent(parent)}`), { response: res });
|
|
319
|
+
}
|
|
320
|
+
return res;
|
|
321
|
+
};
|
|
322
|
+
async function defaultSourceHook(url, fetchOpts, parent) {
|
|
323
|
+
let res = await doFetch(url, fetchOpts, parent), contentType = res.headers.get('Content-Type') || '';
|
|
324
|
+
if (!/^(?:text|application)\/(?:x-)?(?:java|type)script(?:;|$)/i.test(contentType)) {
|
|
325
|
+
throw Error(`Unsupported Content-Type "${contentType}" loading ${url}${fromParent(parent)}. Only JavaScript modules are supported and must be served with a valid MIME type like application/javascript.`);
|
|
326
|
+
}
|
|
327
|
+
return { url: res.url, source: await res.text() };
|
|
328
|
+
}
|
|
329
|
+
const fetchModule = async (reqUrl, fetchOpts, parent) => {
|
|
330
|
+
let mapIntegrity = composedImportMap.integrity[reqUrl];
|
|
331
|
+
fetchOpts =
|
|
332
|
+
mapIntegrity && !fetchOpts.integrity ? { ...fetchOpts, integrity: mapIntegrity } : fetchOpts;
|
|
333
|
+
let { url = reqUrl, source } = await defaultSourceHook(reqUrl, fetchOpts, parent);
|
|
334
|
+
return { url, source };
|
|
335
|
+
};
|
|
336
|
+
const getOrCreateLoad = (url, fetchOpts, parent, source) => {
|
|
337
|
+
if (source && registry[url]) {
|
|
338
|
+
let i = 0;
|
|
339
|
+
while (registry[url + '#' + ++i]) { }
|
|
340
|
+
url += '#' + i;
|
|
341
|
+
}
|
|
342
|
+
let load = registry[url];
|
|
343
|
+
if (load)
|
|
344
|
+
return load;
|
|
345
|
+
registry[url] = load = {
|
|
346
|
+
// url
|
|
347
|
+
u: url,
|
|
348
|
+
// response url
|
|
349
|
+
r: source ? url : undefined,
|
|
350
|
+
// fetchPromise
|
|
351
|
+
f: undefined,
|
|
352
|
+
// source
|
|
353
|
+
S: source,
|
|
354
|
+
// linkPromise
|
|
355
|
+
L: undefined,
|
|
356
|
+
// analysis
|
|
357
|
+
a: undefined,
|
|
358
|
+
// deps
|
|
359
|
+
d: undefined,
|
|
360
|
+
// blobUrl
|
|
361
|
+
b: undefined,
|
|
362
|
+
// shellUrl
|
|
363
|
+
s: undefined,
|
|
364
|
+
// needsShim: does it fail execution in the current native loader?
|
|
365
|
+
n: false,
|
|
366
|
+
// shouldShim: does it need to be loaded by the polyfill loader?
|
|
367
|
+
N: false,
|
|
368
|
+
// meta
|
|
369
|
+
m: null,
|
|
370
|
+
};
|
|
371
|
+
load.f = (async () => {
|
|
372
|
+
if (load.S === undefined) {
|
|
373
|
+
// preload fetch options override fetch options (race)
|
|
374
|
+
;
|
|
375
|
+
({ url: load.r, source: load.S } = await (fetchCache[url] ||
|
|
376
|
+
fetchModule(url, fetchOpts, parent)));
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
load.a = lexer.parse(load.S, load.u);
|
|
380
|
+
}
|
|
381
|
+
catch (e) {
|
|
382
|
+
throwError(e);
|
|
383
|
+
load.a = [[], [], false, false];
|
|
384
|
+
}
|
|
385
|
+
return load;
|
|
386
|
+
})();
|
|
387
|
+
return load;
|
|
388
|
+
};
|
|
389
|
+
const linkLoad = (load, fetchOpts) => {
|
|
390
|
+
if (load.L)
|
|
391
|
+
return;
|
|
392
|
+
load.L = load.f.then(() => {
|
|
393
|
+
let childFetchOpts = fetchOpts;
|
|
394
|
+
let dependencies = load.a[0].map(({ n, d, t, a, se }) => {
|
|
395
|
+
let phaseImport = t >= 4;
|
|
396
|
+
let sourcePhase = phaseImport && t < 6;
|
|
397
|
+
if (phaseImport && t !== 4)
|
|
398
|
+
throw new TypeError('Dynamic source imports and import defer are not supported.');
|
|
399
|
+
// Unlike ESMS's automatic polyfill mode, this explicit loader must retain control of nested
|
|
400
|
+
// dynamic imports even when the currently linked graph can otherwise pass through natively.
|
|
401
|
+
if (d >= 0) {
|
|
402
|
+
load.N = true;
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (d !== -1 || !n)
|
|
406
|
+
return;
|
|
407
|
+
let resolved = resolve(n, load.r || load.u);
|
|
408
|
+
if (resolved.n)
|
|
409
|
+
load.n = true;
|
|
410
|
+
if (resolved.N)
|
|
411
|
+
load.N = true;
|
|
412
|
+
let source = sourcePhase ? '' : undefined;
|
|
413
|
+
if (a > 0) {
|
|
414
|
+
let assertion = load.S.slice(a, se - 1);
|
|
415
|
+
// no need to fetch JSON/CSS if supported, since it's a leaf node, we'll just strip the assertion syntax
|
|
416
|
+
if (assertion.includes('json') || assertion.includes('css'))
|
|
417
|
+
source = '';
|
|
418
|
+
}
|
|
419
|
+
// The ESM wrapper lazily imports this core. Loading the wrapper through the core would
|
|
420
|
+
// recurse and create a second copy of modules that import the wrapper.
|
|
421
|
+
if (nativeModules.has(resolved.r))
|
|
422
|
+
return { l: { u: resolved.r, b: resolved.r }, s: false };
|
|
423
|
+
if (childFetchOpts.integrity)
|
|
424
|
+
childFetchOpts = { ...childFetchOpts, integrity: undefined };
|
|
425
|
+
let child = {
|
|
426
|
+
l: getOrCreateLoad(resolved.r, childFetchOpts, load.r, source),
|
|
427
|
+
s: sourcePhase,
|
|
428
|
+
};
|
|
429
|
+
// assertion case -> inline the CSS / JSON URL directly
|
|
430
|
+
if (source === '')
|
|
431
|
+
child.l.b = child.l.u;
|
|
432
|
+
if (!child.s)
|
|
433
|
+
linkLoad(child.l, fetchOpts);
|
|
434
|
+
// load, sourcePhase
|
|
435
|
+
return child;
|
|
436
|
+
});
|
|
437
|
+
load.d = dependencies.filter((dependency) => dependency !== undefined);
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
const processedImportMaps = new WeakSet();
|
|
441
|
+
const processImportMaps = () => {
|
|
442
|
+
for (let script of document.querySelectorAll('script[type=importmap]'))
|
|
443
|
+
processImportMap(script);
|
|
444
|
+
};
|
|
445
|
+
const processImportMap = (script) => {
|
|
446
|
+
if (processedImportMaps.has(script))
|
|
447
|
+
return;
|
|
448
|
+
processedImportMaps.add(script);
|
|
449
|
+
// we dont currently support external import maps in polyfill mode to match native
|
|
450
|
+
if (script.src)
|
|
451
|
+
return;
|
|
452
|
+
importMapPromise = importMapPromise
|
|
453
|
+
.then(() => {
|
|
454
|
+
composedImportMap = resolveAndComposeImportMap(JSON.parse(script.innerHTML), pageBaseUrl, composedImportMap);
|
|
455
|
+
})
|
|
456
|
+
.catch((e) => {
|
|
457
|
+
if (e instanceof SyntaxError)
|
|
458
|
+
e = new Error(`Unable to parse import map ${e.message} in: ${script.innerHTML}`);
|
|
459
|
+
throwError(e);
|
|
460
|
+
});
|
|
461
|
+
if (!firstImportMap && legacyAcceptingImportMaps)
|
|
462
|
+
importMapPromise.then(() => (firstImportMap = composedImportMap));
|
|
463
|
+
legacyAcceptingImportMaps = false;
|
|
464
|
+
};
|
|
465
|
+
const fetchCache = {};
|
|
466
|
+
const processPreload = (url, fetchOpts) => initPromise.then(() => {
|
|
467
|
+
if (fetchCache[url])
|
|
468
|
+
return fetchCache[url];
|
|
469
|
+
return (fetchCache[url] = fetchModule(url, fetchOpts));
|
|
470
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const hasDocument: boolean;
|
|
2
|
+
export declare const dynamicImport: (u: string) => Promise<Record<string, unknown>>;
|
|
3
|
+
export declare const defaultFetchOpts: {
|
|
4
|
+
credentials: "same-origin";
|
|
5
|
+
};
|
|
6
|
+
export declare const version: string;
|
|
7
|
+
export declare let nonce: string;
|
|
8
|
+
export declare const baseUrl: string;
|
|
9
|
+
export declare const createBlob: (source: string) => string;
|
|
10
|
+
export declare const throwError: (err: unknown) => void;
|
|
11
|
+
export declare const fromParent: (parent?: string) => string;
|
|
12
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,SAAkC,CAAA;AAE1D,eAAO,MAAM,aAAa,MAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAc,CAAA;AAEvF,eAAO,MAAM,gBAAgB;;CAAuD,CAAA;AAEpF,eAAO,MAAM,OAAO,QAAuE,CAAA;AAE3F,eAAO,IAAI,KAAK,QAAK,CAAA;AAMrB,eAAO,MAAM,OAAO,QAQD,CAAA;AAEnB,eAAO,MAAM,UAAU,WAAY,MAAM,KAAG,MAC0B,CAAA;AAKtE,eAAO,MAAM,UAAU,QAAS,OAAO,KAAG,IAEzC,CAAA;AAED,eAAO,MAAM,UAAU,YAAa,MAAM,KAAG,MAAoD,CAAA"}
|