From c3940191602a3a5f56bfd4fe35ef990163870c41 Mon Sep 17 00:00:00 2001 From: Dario Novoa Date: Sun, 20 Mar 2022 15:36:18 -0700 Subject: [PATCH] Dynamic imports priority fix closes #6980 (#7061) --- .../dynamic-imports-high-prio/async.js | 1 + .../dynamic-imports-high-prio/index.js | 1 + .../core/integration-tests/test/javascript.js | 68 ++++++++++++------- .../js/src/helpers/browser/js-loader.js | 6 ++ 4 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js create mode 100644 packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js diff --git a/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js new file mode 100644 index 00000000000..7c645e42fb7 --- /dev/null +++ b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js new file mode 100644 index 00000000000..0a0f551e1ca --- /dev/null +++ b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js @@ -0,0 +1 @@ +export default import('./async').then(() => document.head.children); diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index f58347ca760..39867be8942 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -594,20 +594,20 @@ describe('javascript', function () { let output = await run(b); let headChildren = await output.default; - assert.equal(headChildren.length, 3); + assert.strictEqual(headChildren.length, 4); - assert(headChildren[0].tag === 'script'); - assert(headChildren[0].src.match(/async\..*\.js/)); + assert.strictEqual(headChildren[1].tag, 'script'); + assert(headChildren[1].src.match(/async\..*\.js/)); - assert(headChildren[1].tag === 'link'); - assert(headChildren[1].rel === 'prefetch'); - assert(headChildren[1].as === 'script'); - assert(headChildren[1].href.match(/prefetched\..*\.js/)); + assert.strictEqual(headChildren[2].tag, 'link'); + assert.strictEqual(headChildren[2].rel, 'prefetch'); + assert.strictEqual(headChildren[2].as, 'script'); + assert(headChildren[2].href.match(/prefetched\..*\.js/)); - assert(headChildren[2].tag === 'link'); - assert(headChildren[2].rel === 'prefetch'); - assert(headChildren[2].as === 'style'); - assert(headChildren[2].href.match(/prefetched\..*\.css/)); + assert.strictEqual(headChildren[3].tag, 'link'); + assert.strictEqual(headChildren[3].rel, 'prefetch'); + assert.strictEqual(headChildren[3].as, 'style'); + assert(headChildren[3].href.match(/prefetched\..*\.css/)); }); it('should load additional links that were prefetched', async function () { @@ -623,7 +623,7 @@ describe('javascript', function () { await outputReturn.loadDependency(); let headChildren = outputReturn.children; - assert.equal(headChildren.length, 5); + assert.equal(headChildren.length, 7); let cssBundles = headChildren.filter(child => child.href?.match(/prefetched-loaded\..*\.css/), ); @@ -647,20 +647,17 @@ describe('javascript', function () { let output = await run(b); let headChildren = await output.default; - assert(headChildren.length === 3); - - assert(headChildren[0].tag === 'script'); - assert(headChildren[0].src.match(/async\..*\.js/)); - - assert(headChildren[1].tag === 'link'); - assert(headChildren[1].rel === 'preload'); - assert(headChildren[1].as === 'script'); - assert(headChildren[1].href.match(/preloaded\..*\.js/)); + assert(headChildren.length === 4); assert(headChildren[2].tag === 'link'); assert(headChildren[2].rel === 'preload'); - assert(headChildren[2].as === 'style'); - assert(headChildren[2].href.match(/preloaded\..*\.css/)); + assert(headChildren[2].as === 'script'); + assert(headChildren[2].href.match(/preloaded\..*\.js/)); + + assert(headChildren[3].tag === 'link'); + assert(headChildren[3].rel === 'preload'); + assert(headChildren[3].as === 'style'); + assert(headChildren[3].href.match(/preloaded\..*\.css/)); }); // TODO: Implement when we can evaluate bundles against esmodule targets @@ -874,6 +871,31 @@ describe('javascript', function () { assert.deepEqual(res, {default: 42}); }); + it('dynamic imports loaded as high-priority scripts when not all engines support esmodules natively', async function () { + let b = await bundle( + path.join(__dirname, '/integration/dynamic-imports-high-prio/index.js'), + { + defaultTargetOptions: { + engines: { + browsers: 'IE 11', + }, + }, + }, + ); + + let output = await run(b); + let headChildren = await output.default; + + assert(headChildren[0].tag === 'link'); + assert(headChildren[0].rel === 'preload'); + assert(headChildren[0].as === 'script'); + + assert(headChildren[1].tag === 'script'); + assert(headChildren[1].src.match(/async\..*\.js/)); + + assert(headChildren[0].href === headChildren[1].src); + }); + it('should support bundling workers with dynamic import in both page and worker', async function () { let b = await bundle( path.join(__dirname, '/integration/worker-dynamic/index-async.js'), diff --git a/packages/runtimes/js/src/helpers/browser/js-loader.js b/packages/runtimes/js/src/helpers/browser/js-loader.js index 867fa4f4d2b..0ab0f33f63e 100644 --- a/packages/runtimes/js/src/helpers/browser/js-loader.js +++ b/packages/runtimes/js/src/helpers/browser/js-loader.js @@ -13,6 +13,12 @@ module.exports = cacheLoader(function loadJSBundle(bundle) { return; } + var preloadLink = document.createElement('link'); + preloadLink.href = bundle; + preloadLink.rel = 'preload'; + preloadLink.as = 'script'; + document.head.appendChild(preloadLink); + var script = document.createElement('script'); script.async = true; script.type = 'text/javascript';