importmap-rails 0.3.0 → 0.3.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35f2f43892e0e51811094caf1cc3239ff50cc84d6c25343ac462b77f284797a6
4
- data.tar.gz: 0f91507c1daf180e40744350b7335cb1a24a5bc063963cc7df88b71695de5a35
3
+ metadata.gz: 29a1e2ec6414bcdbd4b6cd4c9726c838ea2f6b0179797f35c23ed0e9769495c1
4
+ data.tar.gz: 760b8781cf2c0a60ee4603440f183e6786c3147f537000b5ff0dd653fef3c754
5
5
  SHA512:
6
- metadata.gz: 96a9a8b0bc81dc2f1f7ea085c9fa9cb765cfaf4545a643f5dac80e299ea9c12c6b3c7597361f67e79f9261c28298c68d0c06aea582efa8736ee79afcf5e0ad68
7
- data.tar.gz: b82ae667a77b3b96665bcf053388b2a2573926c4920d44c2c69316929fbacb7f034dbdd6f11b71fefc2965deb59e954925b5289323e7498328d7ac86a3338c68
6
+ metadata.gz: 7a30aba12a32f3399b6d6e1c2853012866ba9720cf49e8ec4306932f3a0835478aac88a014e95bfda052d7415e5f1a37afb34404edbfd8b8df00e0aa6ffcfd1b
7
+ data.tar.gz: fba823c13bd453195561a892ac36e4855fb4d147b4c5b14099e6ad840b282184927e0496e89506d536e9af56eb93a8e3b267e83a699d46f4f76427230f9c51be
@@ -1 +1 @@
1
- //= require ./es-module-shims@0.12.2.js
1
+ //= require ./es-module-shims@0.12.8.js
@@ -1,6 +1,6 @@
1
- /* ES Module Shims 0.12.2 */
1
+ /* ES Module Shims 0.12.8 */
2
2
  (function () {
3
- // Temporary hack around https://github.com/guybedford/es-module-shims/issues/148
3
+ // Bail on all shimming for Chrome until https://github.com/guybedford/es-module-shims/issues/150
4
4
  if (navigator.userAgent.match("Chrome")) return
5
5
 
6
6
  const resolvedPromise = Promise.resolve();
@@ -16,6 +16,7 @@
16
16
  // support browsers without dynamic import support (eg Firefox 6x)
17
17
  let supportsDynamicImport = false;
18
18
  let supportsJsonAssertions = false;
19
+ let supportsCssAssertions = false;
19
20
  let dynamicImport;
20
21
  try {
21
22
  dynamicImport = (0, eval)('u=>import(u)');
@@ -53,6 +54,7 @@
53
54
  let supportsImportMaps = false;
54
55
 
55
56
  const featureDetectionPromise = Promise.all([
57
+ dynamicImport(createBlob('import"data:text/css,{}"assert{type:"css"}')).then(() => supportsCssAssertions = true, () => {}),
56
58
  dynamicImport(createBlob('import"data:text/json,{}"assert{type:"json"}')).then(() => supportsJsonAssertions = true, () => {}),
57
59
  dynamicImport(createBlob('import.meta')).then(() => supportsImportMeta = true, () => {}),
58
60
  supportsDynamicImport && hasDocument && new Promise(resolve => {
@@ -263,9 +265,13 @@
263
265
  load.n = load.d.some(dep => dep.n);
264
266
  }
265
267
 
268
+ let importMap = { imports: {}, scopes: {} };
269
+ let importMapSrcOrLazy = false;
270
+ let importMapPromise = resolvedPromise;
271
+
266
272
  let waitingForImportMapsInterval;
267
273
  let firstTopLevelProcess = true;
268
- async function topLevelLoad (url, fetchOpts, source, nativelyLoaded) {
274
+ async function topLevelLoad (url, fetchOpts, source, nativelyLoaded, lastStaticLoadPromise) {
269
275
  // no need to even fetch if we have feature support
270
276
  await featureDetectionPromise;
271
277
  if (waitingForImportMapsInterval > 0) {
@@ -278,8 +284,8 @@
278
284
  }
279
285
  await importMapPromise;
280
286
  // early analysis opt-out
281
- if (nativelyLoaded && supportsDynamicImport && supportsImportMeta && supportsImportMaps && !importMapSrcOrLazy) {
282
- // dont reexec inline for polyfills -> just return null
287
+ if (nativelyLoaded && supportsDynamicImport && supportsImportMeta && supportsImportMaps && supportsJsonAssertions && supportsCssAssertions && !importMapSrcOrLazy) {
288
+ // dont reexec inline for polyfills -> just return null (since no module id for executed inline module scripts)
283
289
  return source && nativelyLoaded ? null : dynamicImport(source ? createBlob(source) : url);
284
290
  }
285
291
  await init;
@@ -288,17 +294,30 @@
288
294
  await loadAll(load, seen);
289
295
  lastLoad = undefined;
290
296
  resolveDeps(load, seen);
291
- if (source && !nativelyLoaded && !shimMode && !load.n) {
297
+ await lastStaticLoadPromise;
298
+ if (source && !shimMode && !load.n) {
299
+ if (lastStaticLoadPromise) {
300
+ didExecForReadyPromise = true;
301
+ if (domContentLoaded)
302
+ didExecForDomContentLoaded = true;
303
+ }
292
304
  const module = dynamicImport(createBlob(source));
293
305
  if (shouldRevokeBlobURLs) revokeObjectURLs(Object.keys(seen));
294
306
  return module;
295
307
  }
296
308
  const module = await dynamicImport(load.b);
309
+ if (lastStaticLoadPromise && (!nativelyLoaded || load.b !== load.u)) {
310
+ didExecForReadyPromise = true;
311
+ if (domContentLoaded)
312
+ didExecForDomContentLoaded = true;
313
+ }
297
314
  // if the top-level load is a shell, run its update function
298
315
  if (load.s) {
299
316
  (await dynamicImport(load.s)).u$_(module);
300
317
  }
301
318
  if (shouldRevokeBlobURLs) revokeObjectURLs(Object.keys(seen));
319
+ // when tla is supported, this should return the tla promise as an actual handle
320
+ // so readystate can still correspond to the sync subgraph exec completions
302
321
  return module;
303
322
  }
304
323
 
@@ -323,7 +342,8 @@
323
342
  await featureDetectionPromise;
324
343
  // Make sure all the "in-flight" import maps are loaded and applied.
325
344
  await importMapPromise;
326
- return topLevelLoad(resolve(id, parentUrl).r || throwUnresolved(id, parentUrl), { credentials: 'same-origin' });
345
+ const resolved = await resolve(id, parentUrl);
346
+ return topLevelLoad(resolved.r || throwUnresolved(id, parentUrl), { credentials: 'same-origin' });
327
347
  }
328
348
 
329
349
  self.importShim = importShim;
@@ -334,7 +354,8 @@
334
354
 
335
355
  async function importMetaResolve (id, parentUrl = this.url) {
336
356
  await importMapPromise;
337
- return resolve(id, `${parentUrl}`).r || throwUnresolved(id, parentUrl);
357
+ const resolved = await resolve(id, `${parentUrl}`);
358
+ return resolved.r || throwUnresolved(id, parentUrl);
338
359
  }
339
360
 
340
361
  self._esmsm = meta;
@@ -346,6 +367,7 @@
346
367
  const skip = esmsInitOptions.skip || /^https?:\/\/(cdn\.skypack\.dev|jspm\.dev)\//;
347
368
  const onerror = esmsInitOptions.onerror || ((e) => { throw e; });
348
369
  const shouldRevokeBlobURLs = esmsInitOptions.revokeBlobURLs;
370
+ const noLoadEventRetriggers = esmsInitOptions.noLoadEventRetriggers;
349
371
 
350
372
  function urlJsString (url) {
351
373
  return `'${url.replace(/'/g, "\\'")}'`;
@@ -374,7 +396,7 @@
374
396
  const source = load.S;
375
397
 
376
398
  // edge doesnt execute sibling in order, so we fix this up by ensuring all previous executions are explicit dependencies
377
- let resolvedSource = edge && lastLoad ? `import '${lastLoad}';` : '';
399
+ let resolvedSource = edge && lastLoad ? `import '${lastLoad}';` : '';
378
400
 
379
401
  if (!imports.length) {
380
402
  resolvedSource += source;
@@ -449,7 +471,26 @@
449
471
  const cssContentType = /^text\/css(;|$)/;
450
472
  const wasmContentType = /^application\/wasm(;|$)/;
451
473
 
452
- const fetchOptsMap = new Map();
474
+ const cssUrlRegEx = /url\(\s*(?:(["'])((?:\\.|[^\n\\"'])+)\1|((?:\\.|[^\s,"'()\\])+))\s*\)/g;
475
+
476
+ async function doFetch (url, fetchOpts) {
477
+ const res = await fetchHook(url, fetchOpts);
478
+ if (!res.ok)
479
+ throw new Error(`${res.status} ${res.statusText} ${res.url}`);
480
+ const contentType = res.headers.get('content-type');
481
+ if (jsContentType.test(contentType))
482
+ return { r: res.url, s: await res.text(), t: 'js' };
483
+ else if (jsonContentType.test(contentType))
484
+ return { r: res.url, s: `export default ${await res.text()}`, t: 'json' };
485
+ else if (cssContentType.test(contentType))
486
+ return { r: res.url, s: `var s=new CSSStyleSheet();s.replaceSync(${
487
+ JSON.stringify((await res.text()).replace(cssUrlRegEx, (_match, quotes, relUrl1, relUrl2) => `url(${quotes}${resolveUrl(relUrl1 || relUrl2, url)}${quotes})`))
488
+ });export default s;`, t: 'css' };
489
+ else if (wasmContentType.test(contentType))
490
+ throw new Error('WASM modules not yet supported');
491
+ else
492
+ throw new Error(`Unknown Content-Type "${contentType}"`);
493
+ }
453
494
 
454
495
  function getOrCreateLoad (url, fetchOpts, source) {
455
496
  let load = registry[url];
@@ -476,27 +517,18 @@
476
517
  // shellUrl
477
518
  s: undefined,
478
519
  // needsShim
479
- n: false
520
+ n: false,
521
+ // type
522
+ t: null
480
523
  };
481
524
 
482
525
  load.f = (async () => {
483
526
  if (!source) {
484
527
  // preload fetch options override fetch options (race)
485
- const res = await fetchHook(url, fetchOptsMap.get(url) || fetchOpts);
486
- if (!res.ok)
487
- throw new Error(`${res.status} ${res.statusText} ${res.url}`);
488
- load.r = res.url;
489
- const contentType = res.headers.get('content-type');
490
- if (jsContentType.test(contentType))
491
- source = await res.text();
492
- else if (jsonContentType.test(contentType))
493
- source = `export default ${await res.text()}`;
494
- else if (cssContentType.test(contentType))
495
- throw new Error('CSS modules not yet supported');
496
- else if (wasmContentType.test(contentType))
497
- throw new Error('WASM modules not yet supported');
498
- else
499
- throw new Error(`Unknown Content-Type "${contentType}"`);
528
+ let t;
529
+ ({ r: load.r, s: source, t } = await (fetchCache[url] || doFetch(url, fetchOpts)));
530
+ if (t === 'css' && !supportsCssAssertions || t === 'json' && !supportsJsonAssertions)
531
+ load.n = true;
500
532
  }
501
533
  try {
502
534
  load.a = parse(source, load.u);
@@ -511,13 +543,12 @@
511
543
 
512
544
  load.L = load.f.then(async () => {
513
545
  let childFetchOpts = fetchOpts;
514
- load.d = await Promise.all(load.a[0].map(({ n, d, a }) => {
546
+ load.d = (await Promise.all(load.a[0].map(async ({ n, d, a }) => {
515
547
  if (d >= 0 && !supportsDynamicImport ||
516
- d === 2 && (!supportsImportMeta || source.slice(end, end + 8) === '.resolve') ||
517
- a && !supportsJsonAssertions)
548
+ d === 2 && (!supportsImportMeta || source.slice(end, end + 8) === '.resolve'))
518
549
  load.n = true;
519
550
  if (!n) return;
520
- const { r, m } = resolve(n, load.r || load.u);
551
+ const { r, m } = await resolve(n, load.r || load.u);
521
552
  if (m && (!supportsImportMaps || importMapSrcOrLazy))
522
553
  load.n = true;
523
554
  if (d !== -1) return;
@@ -527,22 +558,13 @@
527
558
  if (childFetchOpts.integrity)
528
559
  childFetchOpts = Object.assign({}, childFetchOpts, { integrity: undefined });
529
560
  return getOrCreateLoad(r, childFetchOpts).f;
530
- }).filter(l => l));
561
+ }))).filter(l => l);
531
562
  });
532
563
 
533
564
  return load;
534
565
  }
535
566
 
536
- let importMap = { imports: {}, scopes: {} };
537
- let importMapSrcOrLazy = false;
538
- let importMapPromise = resolvedPromise;
539
-
540
- if (hasDocument) {
541
- processScripts();
542
- waitingForImportMapsInterval = setInterval(processScripts, 20);
543
- }
544
-
545
- async function processScripts () {
567
+ function processScripts () {
546
568
  if (waitingForImportMapsInterval > 0 && document.readyState !== 'loading') {
547
569
  clearTimeout(waitingForImportMapsInterval);
548
570
  waitingForImportMapsInterval = 0;
@@ -550,29 +572,9 @@
550
572
  for (const link of document.querySelectorAll('link[rel="modulepreload"]'))
551
573
  processPreload(link);
552
574
  for (const script of document.querySelectorAll('script[type="module-shim"],script[type="importmap-shim"],script[type="module"],script[type="importmap"]'))
553
- await processScript(script);
575
+ processScript(script);
554
576
  }
555
577
 
556
- new MutationObserver(mutations => {
557
- for (const mutation of mutations) {
558
- if (mutation.type !== 'childList') continue;
559
- for (const node of mutation.addedNodes) {
560
- if (node.tagName === 'SCRIPT' && node.type)
561
- processScript(node, !firstTopLevelProcess);
562
- else if (node.tagName === 'LINK' && node.rel === 'modulepreload')
563
- processPreload(node);
564
- else if (node.querySelectorAll) {
565
- for (const script of node.querySelectorAll('script[type="module-shim"],script[type="importmap-shim"],script[type="module"],script[type="importmap"]')) {
566
- processScript(script, !firstTopLevelProcess);
567
- }
568
- for (const link of node.querySelectorAll('link[rel=modulepreload]')) {
569
- processPreload(link);
570
- }
571
- }
572
- }
573
- }
574
- }).observe(document, { childList: true, subtree: true });
575
-
576
578
  function getFetchOpts (script) {
577
579
  const fetchOpts = {};
578
580
  if (script.integrity)
@@ -588,12 +590,29 @@
588
590
  return fetchOpts;
589
591
  }
590
592
 
591
- async function processScript (script, dynamic) {
593
+ let staticLoadCnt = 0;
594
+ let didExecForReadyPromise = false;
595
+ let didExecForDomContentLoaded = false;
596
+ let lastStaticLoadPromise = Promise.resolve();
597
+ let domContentLoaded = false;
598
+ document.addEventListener('DOMContentLoaded', () => domContentLoaded = true);
599
+ function staticLoadCheck () {
600
+ staticLoadCnt--;
601
+ if (staticLoadCnt === 0 && !noLoadEventRetriggers) {
602
+ if (didExecForDomContentLoaded)
603
+ document.dispatchEvent(new Event('DOMContentLoaded'));
604
+ if (didExecForReadyPromise && document.readyState === 'complete')
605
+ document.dispatchEvent(new Event('readystatechange'));
606
+ }
607
+ }
608
+
609
+ function processScript (script, dynamic) {
592
610
  if (script.ep) // ep marker = script processed
593
611
  return;
594
612
  const shim = script.type.endsWith('-shim');
595
613
  if (shim) shimMode = true;
596
- const type = shim ? script.type.slice(0, -5) : script.type;
614
+ const type = shimMode ? script.type.slice(0, -5) : script.type;
615
+ // dont process module scripts in shim mode or noshim module scripts in polyfill mode
597
616
  if (!shim && shimMode || script.getAttribute('noshim') !== null)
598
617
  return;
599
618
  // empty inline scripts sometimes show before domready
@@ -601,7 +620,14 @@
601
620
  return;
602
621
  script.ep = true;
603
622
  if (type === 'module') {
604
- await topLevelLoad(script.src || `${baseUrl}?${id++}`, getFetchOpts(script), !script.src && script.innerHTML, !shim).catch(onerror);
623
+ const isReadyScript = document.readyState !== 'complete';
624
+ if (isReadyScript) staticLoadCnt++;
625
+ const p = topLevelLoad(script.src || `${baseUrl}?${id++}`, getFetchOpts(script), !script.src && script.innerHTML, !shimMode, isReadyScript && lastStaticLoadPromise);
626
+ p.catch(onerror);
627
+ if (isReadyScript) {
628
+ lastStaticLoadPromise = p.catch(staticLoadCheck);
629
+ p.then(staticLoadCheck);
630
+ }
605
631
  }
606
632
  else if (type === 'importmap') {
607
633
  importMapPromise = importMapPromise.then(async () => {
@@ -612,20 +638,51 @@
612
638
  }
613
639
  }
614
640
 
641
+ const fetchCache = {};
615
642
  function processPreload (link) {
616
643
  if (link.ep) // ep marker = processed
617
644
  return;
618
645
  link.ep = true;
619
- // prepopulate the load record
620
- const fetchOpts = getFetchOpts(link);
621
- // save preloaded fetch options for later load
622
- fetchOptsMap.set(link.href, fetchOpts);
623
- fetch(link.href, fetchOpts);
646
+ if (fetchCache[link.href])
647
+ return;
648
+ fetchCache[link.href] = doFetch(link.href, getFetchOpts(link));
624
649
  }
625
650
 
626
- function resolve (id, parentUrl) {
627
- const urlResolved = resolveIfNotPlainOrUrl(id, parentUrl);
628
- const resolved = resolveImportMap(importMap, urlResolved || id, parentUrl);
651
+ new MutationObserver(mutations => {
652
+ for (const mutation of mutations) {
653
+ if (mutation.type !== 'childList') continue;
654
+ for (const node of mutation.addedNodes) {
655
+ if (node.tagName === 'SCRIPT' && node.type)
656
+ processScript(node, !firstTopLevelProcess);
657
+ else if (node.tagName === 'LINK' && node.rel === 'modulepreload')
658
+ processPreload(node);
659
+ else if (node.querySelectorAll) {
660
+ for (const script of node.querySelectorAll('script[type="module-shim"],script[type="importmap-shim"],script[type="module"],script[type="importmap"]')) {
661
+ processScript(script, !firstTopLevelProcess);
662
+ }
663
+ for (const link of node.querySelectorAll('link[rel=modulepreload]')) {
664
+ processPreload(link);
665
+ }
666
+ }
667
+ }
668
+ }
669
+ }).observe(document, { childList: true, subtree: true });
670
+
671
+ async function defaultResolve (id, parentUrl) {
672
+ return resolveImportMap(importMap, resolveIfNotPlainOrUrl(id, parentUrl) || id, parentUrl);
673
+ }
674
+
675
+ async function resolve (id, parentUrl) {
676
+ let urlResolved = resolveIfNotPlainOrUrl(id, parentUrl);
677
+
678
+ let resolved;
679
+ if (esmsInitOptions.resolve) {
680
+ resolved = await esmsInitOptions.resolve(id, parentUrl, defaultResolve);
681
+ }
682
+ else {
683
+ resolved = resolveImportMap(importMap, urlResolved || id, parentUrl);
684
+ }
685
+
629
686
  return { r: resolved, m: urlResolved !== resolved };
630
687
  }
631
688
 
@@ -633,4 +690,9 @@
633
690
  throw Error("Unable to resolve specifier '" + id + (parentUrl ? "' from " + parentUrl : "'"));
634
691
  }
635
692
 
693
+ if (hasDocument) {
694
+ processScripts();
695
+ waitingForImportMapsInterval = setInterval(processScripts, 20);
696
+ }
697
+
636
698
  }());
data/lib/importmap/map.rb CHANGED
@@ -76,20 +76,11 @@ class Importmap::Map
76
76
  end
77
77
 
78
78
  def module_name_from(filename, mapping)
79
- filename_without_ext_and_version = filename.to_s.remove(filename.extname).split("@").first
80
-
81
- case
82
- when filename_without_ext_and_version == "index" && mapping.under
83
- mapping.under
84
- when mapping.under
85
- "#{mapping.under}/#{filename_without_ext_and_version}"
86
- else
87
- module_name
88
- end
79
+ [ mapping.under, filename.to_s.remove(filename.extname).remove(/\/?index$/).presence ].compact.join("/")
89
80
  end
90
81
 
91
82
  def module_path_from(filename, mapping)
92
- [ mapping.path || mapping.under, filename.to_s ].join("/")
83
+ [ mapping.path || mapping.under, filename.to_s ].compact.join("/")
93
84
  end
94
85
 
95
86
  def find_javascript_files_in_tree(path)
@@ -1,3 +1,3 @@
1
1
  module Importmap
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: importmap-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-20 00:00:00.000000000 Z
11
+ date: 2021-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.0
27
- description:
27
+ description:
28
28
  email: david@loudthinking.com
29
29
  executables: []
30
30
  extensions: []
@@ -34,7 +34,7 @@ files:
34
34
  - README.md
35
35
  - Rakefile
36
36
  - app/assets/javascripts/es-module-shims.js
37
- - app/assets/javascripts/es-module-shims@0.12.2.js
37
+ - app/assets/javascripts/es-module-shims@0.12.8.js
38
38
  - app/helpers/importmap/importmap_tags_helper.rb
39
39
  - lib/importmap-rails.rb
40
40
  - lib/importmap/engine.rb
@@ -50,7 +50,7 @@ licenses:
50
50
  metadata:
51
51
  homepage_uri: https://github.com/rails/importmap-rails
52
52
  source_code_uri: https://github.com/rails/importmap-rails
53
- post_install_message:
53
+ post_install_message:
54
54
  rdoc_options: []
55
55
  require_paths:
56
56
  - lib
@@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
66
  version: '0'
67
67
  requirements: []
68
68
  rubygems_version: 3.1.4
69
- signing_key:
69
+ signing_key:
70
70
  specification_version: 4
71
71
  summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling
72
72
  or bundling.