es-module-shims 1.5.15 → 1.5.16
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/README.md +5 -5
- package/dist/es-module-shims.js +86 -78
- package/dist/es-module-shims.wasm.js +86 -86
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Shims modern ES Modules features like import maps on top of the baseline modules support in browsers supported by [95% of users](https://caniuse.com/#feat=es6-module).
|
|
4
4
|
|
|
5
|
-
When running in polyfill mode, [the
|
|
5
|
+
When running in polyfill mode, [the 72% of users](https://caniuse.com/import-maps) with import maps entirely bypass the shim code entirely.
|
|
6
6
|
|
|
7
|
-
For the remaining
|
|
7
|
+
For the remaining 28% of users, the highly performant (see [benchmarks](#benchmarks)) production and [CSP-compatible](#csp-support) shim kicks in to rewrite module specifiers driven by the [Web Assembly ES Module Lexer](https://github.com/guybedford/es-module-lexer).
|
|
8
8
|
|
|
9
9
|
The following modules features are polyfilled:
|
|
10
10
|
|
|
@@ -29,7 +29,7 @@ Because we are still using the native module loader the edge cases work out comp
|
|
|
29
29
|
Include ES Module Shims with a `async` attribute on the script, then include an import map and module scripts normally:
|
|
30
30
|
|
|
31
31
|
```html
|
|
32
|
-
<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.
|
|
32
|
+
<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.16/dist/es-module-shims.js"></script>
|
|
33
33
|
|
|
34
34
|
<!-- https://generator.jspm.io/#U2NhYGBkDM0rySzJSU1hKEpNTC5xMLTQM9Az0C1K1jMAAKFS5w0gAA -->
|
|
35
35
|
<script type="importmap">
|
|
@@ -176,8 +176,8 @@ ES Module Shims is designed for production performance. A [comprehensive benchma
|
|
|
176
176
|
|
|
177
177
|
Benchmark summary:
|
|
178
178
|
|
|
179
|
-
* [ES Module Shims Chrome Passthrough](bench/README.md#chrome-passthrough-performance) (for [
|
|
180
|
-
* [ES Module Shims Polyfilling](bench/README.md#native-v-polyfill-performance) (for the remaining [
|
|
179
|
+
* [ES Module Shims Chrome Passthrough](bench/README.md#chrome-passthrough-performance) (for [72% of users](https://caniuse.com/import-maps)) results in ~5ms extra initialization time over native for ES Module Shims fetching, execution and initialization, and on a slow connection the additional non-blocking bandwidth cost of its 10KB compressed download as expected.
|
|
180
|
+
* [ES Module Shims Polyfilling](bench/README.md#native-v-polyfill-performance) (for the remaining [28% of users](https://caniuse.com/import-maps)) is on average 1.4x - 1.5x slower than native module loading, and up to 1.8x slower on slow networks (most likely due to the browser preloader), both for cached and uncached loads, and this result scales linearly up to 10MB and 20k modules loaded executing on the fastest connection in just over 2 seconds in Firefox.
|
|
181
181
|
* [Very large import maps](bench/README.md#large-import-maps-performance) (100s of entries) cost only a few extra milliseconds upfront for the additional loading cost.
|
|
182
182
|
|
|
183
183
|
## Features
|
package/dist/es-module-shims.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* ES Module Shims 1.5.
|
|
1
|
+
/* ES Module Shims 1.5.16 */
|
|
2
2
|
(function () {
|
|
3
3
|
|
|
4
4
|
const hasWindow = typeof window !== 'undefined';
|
|
@@ -258,40 +258,52 @@
|
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
let
|
|
262
|
-
window.addEventListener('error', _err => err = _err);
|
|
263
|
-
const inject = (s, errUrl) => new Promise((resolve, reject) => {
|
|
264
|
-
err = undefined;
|
|
265
|
-
s.ep = true;
|
|
266
|
-
if (nonce)
|
|
267
|
-
s.setAttribute('nonce', nonce);
|
|
268
|
-
|
|
269
|
-
// Safari is unique in supporting module script error events
|
|
270
|
-
s.addEventListener('error', cb);
|
|
271
|
-
s.addEventListener('load', cb);
|
|
272
|
-
|
|
273
|
-
function cb (_err) {
|
|
274
|
-
document.head.removeChild(s);
|
|
275
|
-
if (self._esmsi) {
|
|
276
|
-
resolve(self._esmsi, baseUrl);
|
|
277
|
-
self._esmsi = undefined;
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
reject(!(_err instanceof Event) && _err || err && err.error || new Error(`Error loading or executing the graph of ${errUrl} (check the console for ${s.src}).`));
|
|
281
|
-
err = undefined;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
document.head.appendChild(s);
|
|
286
|
-
});
|
|
261
|
+
let dynamicImport = !hasDocument && (0, eval)('u=>import(u)');
|
|
287
262
|
|
|
288
|
-
|
|
289
|
-
type: 'module',
|
|
290
|
-
src: createBlob(`import*as m from'${url}';self._esmsi=m`)
|
|
291
|
-
}), opts && opts.errUrl || url);
|
|
263
|
+
let supportsDynamicImport;
|
|
292
264
|
|
|
293
|
-
|
|
294
|
-
|
|
265
|
+
const dynamicImportCheck = hasDocument && new Promise(resolve => {
|
|
266
|
+
const s = Object.assign(document.createElement('script'), {
|
|
267
|
+
src: createBlob('self._d=u=>import(u)'),
|
|
268
|
+
ep: true
|
|
269
|
+
});
|
|
270
|
+
s.setAttribute('nonce', nonce);
|
|
271
|
+
s.addEventListener('load', () => {
|
|
272
|
+
if (!(supportsDynamicImport = !!(dynamicImport = self._d))) {
|
|
273
|
+
let err;
|
|
274
|
+
window.addEventListener('error', _err => err = _err);
|
|
275
|
+
dynamicImport = (url, opts) => new Promise((resolve, reject) => {
|
|
276
|
+
const s = Object.assign(document.createElement('script'), {
|
|
277
|
+
type: 'module',
|
|
278
|
+
src: createBlob(`import*as m from'${url}';self._esmsi=m`)
|
|
279
|
+
});
|
|
280
|
+
err = undefined;
|
|
281
|
+
s.ep = true;
|
|
282
|
+
if (nonce)
|
|
283
|
+
s.setAttribute('nonce', nonce);
|
|
284
|
+
// Safari is unique in supporting module script error events
|
|
285
|
+
s.addEventListener('error', cb);
|
|
286
|
+
s.addEventListener('load', cb);
|
|
287
|
+
function cb (_err) {
|
|
288
|
+
document.head.removeChild(s);
|
|
289
|
+
if (self._esmsi) {
|
|
290
|
+
resolve(self._esmsi, baseUrl);
|
|
291
|
+
self._esmsi = undefined;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
reject(!(_err instanceof Event) && _err || err && err.error || new Error(`Error loading ${opts && opts.errUrl || url} (${s.src}).`));
|
|
295
|
+
err = undefined;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
document.head.appendChild(s);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
document.head.removeChild(s);
|
|
302
|
+
delete self._d;
|
|
303
|
+
resolve();
|
|
304
|
+
});
|
|
305
|
+
document.head.appendChild(s);
|
|
306
|
+
});
|
|
295
307
|
|
|
296
308
|
// support browsers without dynamic import support (eg Firefox 6x)
|
|
297
309
|
let supportsJsonAssertions = false;
|
|
@@ -299,53 +311,49 @@
|
|
|
299
311
|
|
|
300
312
|
let supportsImportMaps = hasDocument && HTMLScriptElement.supports ? HTMLScriptElement.supports('importmap') : false;
|
|
301
313
|
let supportsImportMeta = supportsImportMaps;
|
|
302
|
-
let supportsDynamicImport = false;
|
|
303
314
|
|
|
304
|
-
const
|
|
305
|
-
|
|
315
|
+
const importMetaCheck = 'import.meta';
|
|
316
|
+
const cssModulesCheck = `import"x"assert{type:"css"}`;
|
|
317
|
+
const jsonModulesCheck = `import"x"assert{type:"json"}`;
|
|
318
|
+
|
|
319
|
+
const featureDetectionPromise = Promise.resolve(dynamicImportCheck).then(() => {
|
|
320
|
+
if (!supportsDynamicImport || supportsImportMaps && !cssModulesEnabled && !jsonModulesEnabled)
|
|
306
321
|
return;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if ('srcdoc' in iframe)
|
|
343
|
-
iframe.srcdoc = importMapTest;
|
|
344
|
-
else
|
|
345
|
-
iframe.contentDocument.write(importMapTest);
|
|
346
|
-
document.head.appendChild(iframe);
|
|
347
|
-
});
|
|
348
|
-
}
|
|
322
|
+
|
|
323
|
+
if (!hasDocument)
|
|
324
|
+
return Promise.all([
|
|
325
|
+
supportsImportMaps || dynamicImport(createBlob(importMetaCheck)).then(() => supportsImportMeta = true, noop),
|
|
326
|
+
cssModulesEnabled && dynamicImport(createBlob(cssModulesCheck.replace('x', createBlob('', 'text/css')))).then(() => supportsCssAssertions = true, noop),
|
|
327
|
+
jsonModulesEnabled && dynamicImport(createBlob(jsonModulescheck.replace('x', createBlob('{}', 'text/json')))).then(() => supportsJsonAssertions = true, noop),
|
|
328
|
+
]);
|
|
329
|
+
|
|
330
|
+
return new Promise(resolve => {
|
|
331
|
+
const iframe = document.createElement('iframe');
|
|
332
|
+
iframe.style.display = 'none';
|
|
333
|
+
iframe.setAttribute('nonce', nonce);
|
|
334
|
+
function cb ({ data: [a, b, c, d] }) {
|
|
335
|
+
supportsImportMaps = a;
|
|
336
|
+
supportsImportMeta = b;
|
|
337
|
+
supportsCssAssertions = c;
|
|
338
|
+
supportsJsonAssertions = d;
|
|
339
|
+
resolve();
|
|
340
|
+
document.head.removeChild(iframe);
|
|
341
|
+
window.removeEventListener('message', cb, false);
|
|
342
|
+
}
|
|
343
|
+
window.addEventListener('message', cb, false);
|
|
344
|
+
|
|
345
|
+
const importMapTest = `<script nonce=${nonce}>const b=(s,type='text/javascript')=>URL.createObjectURL(new Blob([s],{type}));document.head.appendChild(Object.assign(document.createElement('script'),{type:'importmap',nonce:"${nonce}",innerText:\`{"imports":{"x":"\${b('')}"}}\`}));Promise.all([${
|
|
346
|
+
supportsImportMaps ? 'true,true' : `'x',b('${importMetaCheck}')`}, ${cssModulesEnabled ? `b('${cssModulesCheck}'.replace('x',b('','text/css')))` : 'false'}, ${
|
|
347
|
+
jsonModulesEnabled ? `b('${jsonModulesCheck}'.replace('x',b('{}','text/json')))` : 'false'}].map(x =>typeof x==='string'?import(x).then(x =>!!x,()=>false):x)).then(a=>parent.postMessage(a,'*'))<${''}/script>`;
|
|
348
|
+
// setting srcdoc is not supported in React native webviews on iOS
|
|
349
|
+
// setting src to a blob URL results in a navigation event in webviews
|
|
350
|
+
// document.write gives usability warnings
|
|
351
|
+
if ('srcdoc' in iframe)
|
|
352
|
+
iframe.srcdoc = importMapTest;
|
|
353
|
+
else
|
|
354
|
+
iframe.contentDocument.write(importMapTest);
|
|
355
|
+
document.head.appendChild(iframe);
|
|
356
|
+
});
|
|
349
357
|
});
|
|
350
358
|
|
|
351
359
|
/* es-module-lexer 1.0.3 */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* ES Module Shims Wasm 1.5.
|
|
1
|
+
/* ES Module Shims Wasm 1.5.16 */
|
|
2
2
|
(function () {
|
|
3
3
|
|
|
4
4
|
const hasWindow = typeof window !== 'undefined';
|
|
@@ -258,48 +258,52 @@
|
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
let
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
err = undefined;
|
|
261
|
+
let dynamicImport = !hasDocument && (0, eval)('u=>import(u)');
|
|
262
|
+
|
|
263
|
+
let supportsDynamicImport;
|
|
264
|
+
|
|
265
|
+
const dynamicImportCheck = hasDocument && new Promise(resolve => {
|
|
266
|
+
const s = Object.assign(document.createElement('script'), {
|
|
267
|
+
src: createBlob('self._d=u=>import(u)'),
|
|
268
|
+
ep: true
|
|
269
|
+
});
|
|
270
|
+
s.setAttribute('nonce', nonce);
|
|
271
|
+
s.addEventListener('load', () => {
|
|
272
|
+
if (!(supportsDynamicImport = !!(dynamicImport = self._d))) {
|
|
273
|
+
let err;
|
|
274
|
+
window.addEventListener('error', _err => err = _err);
|
|
275
|
+
dynamicImport = (url, opts) => new Promise((resolve, reject) => {
|
|
276
|
+
const s = Object.assign(document.createElement('script'), {
|
|
277
|
+
type: 'module',
|
|
278
|
+
src: createBlob(`import*as m from'${url}';self._esmsi=m`)
|
|
279
|
+
});
|
|
280
|
+
err = undefined;
|
|
281
|
+
s.ep = true;
|
|
282
|
+
if (nonce)
|
|
283
|
+
s.setAttribute('nonce', nonce);
|
|
284
|
+
// Safari is unique in supporting module script error events
|
|
285
|
+
s.addEventListener('error', cb);
|
|
286
|
+
s.addEventListener('load', cb);
|
|
287
|
+
function cb (_err) {
|
|
288
|
+
document.head.removeChild(s);
|
|
289
|
+
if (self._esmsi) {
|
|
290
|
+
resolve(self._esmsi, baseUrl);
|
|
291
|
+
self._esmsi = undefined;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
reject(!(_err instanceof Event) && _err || err && err.error || new Error(`Error loading ${opts && opts.errUrl || url} (${s.src}).`));
|
|
295
|
+
err = undefined;
|
|
296
|
+
}
|
|
298
297
|
}
|
|
298
|
+
document.head.appendChild(s);
|
|
299
299
|
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
}
|
|
301
|
+
document.head.removeChild(s);
|
|
302
|
+
delete self._d;
|
|
303
|
+
resolve();
|
|
304
|
+
});
|
|
305
|
+
document.head.appendChild(s);
|
|
306
|
+
});
|
|
303
307
|
|
|
304
308
|
// support browsers without dynamic import support (eg Firefox 6x)
|
|
305
309
|
let supportsJsonAssertions = false;
|
|
@@ -307,53 +311,49 @@
|
|
|
307
311
|
|
|
308
312
|
let supportsImportMaps = hasDocument && HTMLScriptElement.supports ? HTMLScriptElement.supports('importmap') : false;
|
|
309
313
|
let supportsImportMeta = supportsImportMaps;
|
|
310
|
-
let supportsDynamicImport = false;
|
|
311
314
|
|
|
312
|
-
const
|
|
313
|
-
|
|
315
|
+
const importMetaCheck = 'import.meta';
|
|
316
|
+
const cssModulesCheck = `import"x"assert{type:"css"}`;
|
|
317
|
+
const jsonModulesCheck = `import"x"assert{type:"json"}`;
|
|
318
|
+
|
|
319
|
+
const featureDetectionPromise = Promise.resolve(dynamicImportCheck).then(() => {
|
|
320
|
+
if (!supportsDynamicImport || supportsImportMaps && !cssModulesEnabled && !jsonModulesEnabled)
|
|
314
321
|
return;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if ('srcdoc' in iframe)
|
|
351
|
-
iframe.srcdoc = importMapTest;
|
|
352
|
-
else
|
|
353
|
-
iframe.contentDocument.write(importMapTest);
|
|
354
|
-
document.head.appendChild(iframe);
|
|
355
|
-
});
|
|
356
|
-
}
|
|
322
|
+
|
|
323
|
+
if (!hasDocument)
|
|
324
|
+
return Promise.all([
|
|
325
|
+
supportsImportMaps || dynamicImport(createBlob(importMetaCheck)).then(() => supportsImportMeta = true, noop),
|
|
326
|
+
cssModulesEnabled && dynamicImport(createBlob(cssModulesCheck.replace('x', createBlob('', 'text/css')))).then(() => supportsCssAssertions = true, noop),
|
|
327
|
+
jsonModulesEnabled && dynamicImport(createBlob(jsonModulescheck.replace('x', createBlob('{}', 'text/json')))).then(() => supportsJsonAssertions = true, noop),
|
|
328
|
+
]);
|
|
329
|
+
|
|
330
|
+
return new Promise(resolve => {
|
|
331
|
+
const iframe = document.createElement('iframe');
|
|
332
|
+
iframe.style.display = 'none';
|
|
333
|
+
iframe.setAttribute('nonce', nonce);
|
|
334
|
+
function cb ({ data: [a, b, c, d] }) {
|
|
335
|
+
supportsImportMaps = a;
|
|
336
|
+
supportsImportMeta = b;
|
|
337
|
+
supportsCssAssertions = c;
|
|
338
|
+
supportsJsonAssertions = d;
|
|
339
|
+
resolve();
|
|
340
|
+
document.head.removeChild(iframe);
|
|
341
|
+
window.removeEventListener('message', cb, false);
|
|
342
|
+
}
|
|
343
|
+
window.addEventListener('message', cb, false);
|
|
344
|
+
|
|
345
|
+
const importMapTest = `<script nonce=${nonce}>const b=(s,type='text/javascript')=>URL.createObjectURL(new Blob([s],{type}));document.head.appendChild(Object.assign(document.createElement('script'),{type:'importmap',nonce:"${nonce}",innerText:\`{"imports":{"x":"\${b('')}"}}\`}));Promise.all([${
|
|
346
|
+
supportsImportMaps ? 'true,true' : `'x',b('${importMetaCheck}')`}, ${cssModulesEnabled ? `b('${cssModulesCheck}'.replace('x',b('','text/css')))` : 'false'}, ${
|
|
347
|
+
jsonModulesEnabled ? `b('${jsonModulesCheck}'.replace('x',b('{}','text/json')))` : 'false'}].map(x =>typeof x==='string'?import(x).then(x =>!!x,()=>false):x)).then(a=>parent.postMessage(a,'*'))<${''}/script>`;
|
|
348
|
+
// setting srcdoc is not supported in React native webviews on iOS
|
|
349
|
+
// setting src to a blob URL results in a navigation event in webviews
|
|
350
|
+
// document.write gives usability warnings
|
|
351
|
+
if ('srcdoc' in iframe)
|
|
352
|
+
iframe.srcdoc = importMapTest;
|
|
353
|
+
else
|
|
354
|
+
iframe.contentDocument.write(importMapTest);
|
|
355
|
+
document.head.appendChild(iframe);
|
|
356
|
+
});
|
|
357
357
|
});
|
|
358
358
|
|
|
359
359
|
/* es-module-lexer 1.0.3 */
|