importmap-rails 0.3.0 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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.