es-module-shims 1.10.1 → 2.0.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/README.md +105 -57
- package/dist/es-module-shims.debug.js +716 -581
- package/dist/es-module-shims.js +702 -574
- package/dist/es-module-shims.wasm.js +703 -575
- package/package.json +3 -2
- package/dist/es-module-shims.dev.js +0 -1624
- package/dist/es-module-shims.wasm.dev.js +0 -1071
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Because we are still using the native module loader the edge cases work out comp
|
|
|
27
27
|
Include ES Module Shims with a `async` attribute on the script, then include an import map and module scripts normally:
|
|
28
28
|
|
|
29
29
|
```html
|
|
30
|
-
<script async src="https://ga.jspm.io/npm:es-module-shims@
|
|
30
|
+
<script async src="https://ga.jspm.io/npm:es-module-shims@2.0.0/dist/es-module-shims.js"></script>
|
|
31
31
|
|
|
32
32
|
<!-- https://generator.jspm.io/#U2NhYGBkDM0rySzJSU1hKEpNTC5xMLTQM9Az0C1K1jMAAKFS5w0gAA -->
|
|
33
33
|
<script type="importmap">
|
|
@@ -62,9 +62,9 @@ This error is important - it means that the native browser loader didn't execute
|
|
|
62
62
|
at link time, and before execution time. And this is what allows the polyfill to be able to reexecute the modules and their dependencies
|
|
63
63
|
without risk of duplicate execution.
|
|
64
64
|
|
|
65
|
-
The ES Module Shims polyfill will analyze the browser to
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
The ES Module Shims polyfill will analyze the browser to check its fine-grained support for various import maps and modules features.
|
|
66
|
+
If it is deeemed to support a baseline set of features, and multiple import maps are not in use, the polyfill will do no further work. Otherwise, it
|
|
67
|
+
will analyze all module scripts on the page to see if any of them have static module syntax that would fail. If found, that graph will then be reexecuted through ES Module Shims using its internal rewriting of import statements to polyfill features.
|
|
68
68
|
|
|
69
69
|
When the polyfill kicks in another console log message is output(which can be disabled or customized via the [polyfill hook](#polyfill-hook)):
|
|
70
70
|
|
|
@@ -72,6 +72,9 @@ When the polyfill kicks in another console log message is output(which can be di
|
|
|
72
72
|
^^ Module error above is polyfilled and can be ignored ^^
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
The fetch options used by the polyfill are carefully followed per the spec. In older Firefox and Safari this fetch network cache is
|
|
76
|
+
not fully shared with the polyfill so separate entries can be seen in the network tab, network-level cache coalescing is still seen at the very least.
|
|
77
|
+
|
|
75
78
|
### Polyfill Edge Case: Dynamic Import
|
|
76
79
|
|
|
77
80
|
Only static link-time errors are polyfilled, not runtime errors.
|
|
@@ -124,45 +127,52 @@ If a static failure is not possible and dynamic import must be used, one alterna
|
|
|
124
127
|
|
|
125
128
|
When running in polyfill mode, it can be thought of that are effectively two loaders running on the page - the ES Module Shims polyfill loader, and the native loader.
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
Whenever possible, the polyfill loader will share native modules that can be correctly executed, with one exception per the previous section - modules which use dynamic import, which are imported as dependencies of modules which require polyfill features.
|
|
128
131
|
|
|
129
|
-
|
|
132
|
+
For example consider two shimmed modules, both of which use import maps:
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
`shim-a.js`
|
|
135
|
+
```js
|
|
136
|
+
import 'mapped-dep-a';
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`shim-b.js`
|
|
140
|
+
```js
|
|
141
|
+
import 'mapped-dep-b';
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
where `mapped-dep-a` resolves to `/dep-a.js` and `mapped-dep-b` resolves to `/dep-b.js`, respectively containing:
|
|
145
|
+
|
|
146
|
+
`/dep-a.js`
|
|
147
|
+
```js
|
|
148
|
+
console.log('dep a');
|
|
145
149
|
```
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
`/dep-b.js`
|
|
152
|
+
```js
|
|
153
|
+
console.log('dep b');
|
|
154
|
+
import(expr);
|
|
149
155
|
```
|
|
150
156
|
|
|
151
|
-
|
|
157
|
+
While the shim modules are always loaded in the shim loader, the `dep-a.js` module is loaded from the native loader since it does not require any polyfilling.
|
|
158
|
+
|
|
159
|
+
On th other hand, `dep-b.js` is loaded from the shim loader as well _because it was loaded by a polyfilled parent graph and uses dynamic import_. Within the polyfill loader, the `import(expr)` is replaced with `importShim(expr)` to support import maps. This is in contrast to top-level native graphs which do not get shimmed per the previous section.
|
|
152
160
|
|
|
153
|
-
|
|
161
|
+
As a result, `import('/dep-a.js')` in the native loader is the same instance as the `dep-a.js` loaded by `shim-a.js`, but `dep-b` would be executed twice if passed into `import('/dep-b.js')` - the shim loader and native loader instances are separate, and `dep b` would be logged twice.
|
|
154
162
|
|
|
155
|
-
|
|
163
|
+
Note that this is the ONLY scenario in which instance sharing will not otherwise occur in the polyfill loader.
|
|
164
|
+
|
|
165
|
+
A workaround to this instance sharing case is to use the [`skip` option](#skip) to list modules which should always be loaded via the native loader (which also saves on analysis work time for performance):
|
|
156
166
|
|
|
157
167
|
```html
|
|
158
168
|
<script type="esms-options">
|
|
159
169
|
{
|
|
160
|
-
"skip": ["/dep.js"]
|
|
170
|
+
"skip": ["/dep-b.js"]
|
|
161
171
|
}
|
|
162
172
|
</script>
|
|
163
173
|
```
|
|
164
174
|
|
|
165
|
-
The above would then fully cause dependency module instance to be shared between ES Module Shims and the native loader, with the polyfill then logging `"
|
|
175
|
+
The above would then fully cause dependency module instance of dep-b to be shared between ES Module Shims and the native loader, with the polyfill then logging `"dep b"` only once.
|
|
166
176
|
|
|
167
177
|
#### No Shim Scripts
|
|
168
178
|
|
|
@@ -217,6 +227,7 @@ Browser Compatibility on baseline ES modules support **with** ES Module Shims:
|
|
|
217
227
|
| [modulepreload](#modulepreload) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
218
228
|
| [Import Maps](#import-maps) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
219
229
|
| [Import Map Integrity](#import-map-integrity) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
230
|
+
| [Multiple Import Maps](#multiple-import-maps) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
220
231
|
| [JSON Modules](#json-modules) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
221
232
|
| [CSS Modules](#css-modules) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
222
233
|
| [Wasm Modules](#wasm-modules) | 89+ | 89+ | 15+ |
|
|
@@ -228,7 +239,8 @@ Browser compatibility **without** ES Module Shims:
|
|
|
228
239
|
| [modulepreload](#modulepreload) | 66+ | 115+ | 17.5+ |
|
|
229
240
|
| [import.meta.url](#importmetaurl) | ~76+ | ~67+ | ~12+ |
|
|
230
241
|
| [Import Maps](#import-maps) | 89+ | 108+ | 16.4+ |
|
|
231
|
-
| [Import Map Integrity](#import-map-integrity) |
|
|
242
|
+
| [Import Map Integrity](#import-map-integrity) | 127+ | :x: | :x: |
|
|
243
|
+
| [Multiple Import Maps](#multiple-import-maps) | Pending | :x: | :x: |
|
|
232
244
|
| [JSON Modules](#json-modules) | 123+ | :x: | 17.2+ |
|
|
233
245
|
| [CSS Modules](#css-modules) | 123+ | :x: | :x: |
|
|
234
246
|
| [Wasm Modules](#wasm-modules) | :x: | :x: | :x: |
|
|
@@ -268,14 +280,6 @@ Using this polyfill we can write:
|
|
|
268
280
|
|
|
269
281
|
All modules are still loaded with the native browser module loader, but with their specifiers rewritten then executed as Blob URLs, so there is a relatively minimal overhead to using a polyfill approach like this.
|
|
270
282
|
|
|
271
|
-
#### Multiple Import Maps
|
|
272
|
-
|
|
273
|
-
Multiple import maps are not currently supported in any native implementation, Chromium support is currently being tracked in https://bugs.chromium.org/p/chromium/issues/detail?id=927119.
|
|
274
|
-
|
|
275
|
-
In polyfill mode, multiple import maps are therefore not supported.
|
|
276
|
-
|
|
277
|
-
In shim mode, support for multiple `importmap-shim` scripts follows the [import map extensions](https://github.com/guybedford/import-maps-extensions) proposal.
|
|
278
|
-
|
|
279
283
|
#### External Import Maps
|
|
280
284
|
|
|
281
285
|
External import maps (using a `"src"` attribute) are not currently supported in any native implementation.
|
|
@@ -284,9 +288,13 @@ In polyfill mode, external import maps are therefore not supported.
|
|
|
284
288
|
|
|
285
289
|
In shim mode, external import maps are fully supported.
|
|
286
290
|
|
|
287
|
-
|
|
291
|
+
### Multiple Import Maps
|
|
292
|
+
|
|
293
|
+
Multiple import maps have been recently implemented in Chromium in https://bugs.chromium.org/p/chromium/issues/detail?id=927119, including supporting dynamically loading import maps even after modules have been loaded.
|
|
294
|
+
|
|
295
|
+
In polyfill mode, multiple import maps are supported.
|
|
288
296
|
|
|
289
|
-
Support for dynamically injecting import maps with JavaScript via
|
|
297
|
+
Support for dynamically injecting import maps with JavaScript via e.g.:
|
|
290
298
|
|
|
291
299
|
```js
|
|
292
300
|
document.body.appendChild(Object.assign(document.createElement('script'), {
|
|
@@ -295,11 +303,64 @@ document.body.appendChild(Object.assign(document.createElement('script'), {
|
|
|
295
303
|
}));
|
|
296
304
|
```
|
|
297
305
|
|
|
298
|
-
is
|
|
306
|
+
is also provided using mutation observers.
|
|
307
|
+
|
|
308
|
+
The caveat for multiple import map support polyfill support in browsers that only support a single import map is per the usual "polyfill rule" for es-module-shims - only those top-level graphs with static import feailures can be polyfilled.
|
|
309
|
+
|
|
310
|
+
Therefore, imports that would otherwise be supported fine by the first map can't be polyfilled, for example:
|
|
311
|
+
|
|
312
|
+
```html
|
|
313
|
+
<script type="importmap">
|
|
314
|
+
{
|
|
315
|
+
"imports": {
|
|
316
|
+
"a": "/a.js"
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
</script>
|
|
320
|
+
<script type="importmap">
|
|
321
|
+
{
|
|
322
|
+
"scopes": {
|
|
323
|
+
"/": {
|
|
324
|
+
"a": "/b.js"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
</script>
|
|
329
|
+
<script type="module">
|
|
330
|
+
import 'a';
|
|
331
|
+
</script>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
In the above, browsers with single import maps support will resolve `/a.js` and the polyfill will not apply, while browsers without any import maps support will be polyfilled to resolve `/b.js`.
|
|
335
|
+
|
|
336
|
+
Instead, following the usual advice, make sure to design the app to either have static failures or not on all polyfill environments to get well-defined polyfill behaviour:
|
|
337
|
+
|
|
338
|
+
```html
|
|
339
|
+
<script type="importmap">
|
|
340
|
+
{
|
|
341
|
+
"imports": {
|
|
342
|
+
"a": "/a.js"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
</script>
|
|
346
|
+
<script type="importmap">
|
|
347
|
+
{
|
|
348
|
+
"imports": {
|
|
349
|
+
"b": "/b.js"
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
</script>
|
|
353
|
+
<script type="module">
|
|
354
|
+
import 'a';
|
|
355
|
+
</script>
|
|
356
|
+
<script type="module">
|
|
357
|
+
import 'b';
|
|
358
|
+
</script>
|
|
359
|
+
```
|
|
299
360
|
|
|
300
|
-
|
|
361
|
+
The above will then correctly execute both `a` and `b`, with only the `b` importer being polyfilled.
|
|
301
362
|
|
|
302
|
-
|
|
363
|
+
Note that shimmed graphs will always support correct mappings - the above rules only apply to the initial polyfill engagement.
|
|
303
364
|
|
|
304
365
|
#### Reading current import map state
|
|
305
366
|
|
|
@@ -529,10 +590,8 @@ window.esmsInitOptions = {
|
|
|
529
590
|
polyfillEnable: ['css-modules', 'json-modules'], // default empty
|
|
530
591
|
// Custom CSP nonce
|
|
531
592
|
nonce: 'n0nce', // default is automatic detection
|
|
532
|
-
// Don't retrigger load events on module scripts (DOMContentLoaded, domready)
|
|
593
|
+
// Don't retrigger load events on module scripts (DOMContentLoaded, domready, window 'onload')
|
|
533
594
|
noLoadEventRetriggers: true, // default false
|
|
534
|
-
// Retrigger window 'load' event (will be combined into load event above on next major)
|
|
535
|
-
globalLoadEventRetrigger: true, // default false
|
|
536
595
|
// Skip source analysis of certain URLs for full native passthrough
|
|
537
596
|
skip: /^https:\/\/cdn\.com/, // defaults to null
|
|
538
597
|
// Clean up blob URLs after execution
|
|
@@ -659,7 +718,7 @@ Alternatively, add a `blob:` URL policy with the CSP build to get CSP compatibil
|
|
|
659
718
|
|
|
660
719
|
### No Load Event Retriggers
|
|
661
720
|
|
|
662
|
-
Because of the extra processing done by ES Module Shims it is possible for static module scripts to execute after the `DOMContentLoaded` or `
|
|
721
|
+
Because of the extra processing done by ES Module Shims it is possible for static module scripts to execute after the `DOMContentLoaded`, `readystatechange` or window `load` events they expect, which can cause missed attachment.
|
|
663
722
|
|
|
664
723
|
In addition, script elements will also have their load events refired when polyfilled.
|
|
665
724
|
|
|
@@ -670,20 +729,13 @@ In such a case, this double event firing can be disabled with the `noLoadEventRe
|
|
|
670
729
|
```js
|
|
671
730
|
<script type="esms-options">
|
|
672
731
|
{
|
|
673
|
-
// do not re-trigger DOM events (onreadystatechange, DOMContentLoaded)
|
|
732
|
+
// do not re-trigger DOM events (onreadystatechange, DOMContentLoaded, window 'onload')
|
|
674
733
|
"noLoadEventRetriggers": true
|
|
675
734
|
}
|
|
676
735
|
</script>
|
|
677
736
|
<script async src="es-module-shims.js"></script>
|
|
678
737
|
```
|
|
679
738
|
|
|
680
|
-
### Global Load Event Retrigger
|
|
681
|
-
|
|
682
|
-
In ES Module Shims 1.x, load event retriggers only apply to `DOMContentLoaded` and `readystatechange` and not to the window `load` event.
|
|
683
|
-
To enable the window / worker `'load'` event, set `globalLoadEventRetrigger: true`.
|
|
684
|
-
|
|
685
|
-
In the next major version, this will be the default for load events, at which point only `noLoadEventRetriggers` will remain.
|
|
686
|
-
|
|
687
739
|
### Skip
|
|
688
740
|
|
|
689
741
|
When loading modules that you know will only use baseline modules features, it is possible to set a rule to explicitly opt-out modules from being polyfilled to always load and be referenced through the native loader only. This enables instance sharing with the native loader and also improves performance because those modules then do not need to be processed or transformed at all, so that only local application code is handled and not library code.
|
|
@@ -840,10 +892,6 @@ If the resolve hook should apply for all modules in the entire module graph, mak
|
|
|
840
892
|
</script>
|
|
841
893
|
```
|
|
842
894
|
|
|
843
|
-
Support for an asynchronous resolve hook has been deprecated as of 1.5.0 and will be removed in the next major.
|
|
844
|
-
|
|
845
|
-
Instead async work should be done with the import hook.
|
|
846
|
-
|
|
847
895
|
#### Meta Hook
|
|
848
896
|
|
|
849
897
|
The meta hook allows customizing the `import.meta` object in each module scope.
|