mirror of https://github.com/webpack/webpack.git
fix: use rel modulepreload for esm modules
This commit is contained in:
parent
1018ca80b3
commit
56efad7750
|
|
@ -250,17 +250,19 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
linkPreload.call(
|
||||
Template.asString([
|
||||
"var link = document.createElement('link');",
|
||||
scriptType
|
||||
? `link.type = ${JSON.stringify(scriptType)};`
|
||||
: "",
|
||||
scriptType === "module"
|
||||
? ""
|
||||
: `link.type = ${JSON.stringify(scriptType)};`,
|
||||
"link.charset = 'utf-8';",
|
||||
`if (${RuntimeGlobals.scriptNonce}) {`,
|
||||
Template.indent(
|
||||
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
|
||||
),
|
||||
"}",
|
||||
'link.rel = "preload";',
|
||||
'link.as = "script";',
|
||||
scriptType === "module"
|
||||
? 'link.rel = "modulepreload";'
|
||||
: 'link.rel = "preload";',
|
||||
scriptType === "module" ? "" : 'link.as = "script";',
|
||||
`link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId);`,
|
||||
crossOriginLoading
|
||||
? crossOriginLoading === "use-credentials"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
export default function() {
|
||||
import(/* webpackPrefetch: true, webpackChunkName: "chunk1-a" */ "./chunk1-a");
|
||||
import(/* webpackPreload: true, webpackChunkName: "chunk1-b" */ "./chunk1-b");
|
||||
import(/* webpackPrefetch: 10, webpackChunkName: "chunk1-c" */ "./chunk1-c");
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export default function() {
|
||||
import(/* webpackPrefetch: true, webpackChunkName: "chunk1-a" */ "./chunk1-a");
|
||||
import(/* webpackPreload: true, webpackChunkName: "chunk1-b" */ "./chunk1-b");
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// This config need to be set on initial evaluation to be effective
|
||||
__webpack_nonce__ = "nonce";
|
||||
__webpack_public_path__ = "https://example.com/public/path/";
|
||||
|
||||
it("should prefetch and preload child chunks on chunk load", () => {
|
||||
let link, script;
|
||||
|
||||
expect(document.head._children).toHaveLength(1);
|
||||
|
||||
// Test prefetch from entry chunk
|
||||
link = document.head._children[0];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1.js");
|
||||
|
||||
const promise = import(
|
||||
/* webpackChunkName: "chunk1", webpackPrefetch: true */ "./chunk1"
|
||||
);
|
||||
|
||||
expect(document.head._children).toHaveLength(3);
|
||||
|
||||
// Test normal script loading
|
||||
script = document.head._children[1];
|
||||
expect(script._type).toBe("script");
|
||||
expect(script.src).toBe("https://example.com/public/path/chunk1.js");
|
||||
expect(script.getAttribute("nonce")).toBe("nonce");
|
||||
expect(script.crossOrigin).toBe("anonymous");
|
||||
expect(script.onload).toBeTypeOf("function");
|
||||
|
||||
// Test preload of chunk1-b
|
||||
link = document.head._children[2];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("preload");
|
||||
expect(link.as).toBe("script");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-b.js");
|
||||
expect(link.charset).toBe("utf-8");
|
||||
expect(link.getAttribute("nonce")).toBe("nonce");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
// Run the script
|
||||
__non_webpack_require__("./chunk1.js");
|
||||
|
||||
script.onload();
|
||||
|
||||
return promise.then(() => {
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
|
||||
// Test prefetching for chunk1-c and chunk1-a in this order
|
||||
link = document.head._children[2];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-c.js");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
link = document.head._children[3];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-a.js");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
const promise2 = import(
|
||||
/* webpackChunkName: "chunk1", webpackPrefetch: true */ "./chunk1"
|
||||
);
|
||||
|
||||
// Loading chunk1 again should not trigger prefetch/preload
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
|
||||
const promise3 = import(/* webpackChunkName: "chunk2" */ "./chunk2");
|
||||
|
||||
expect(document.head._children).toHaveLength(5);
|
||||
|
||||
// Test normal script loading
|
||||
script = document.head._children[4];
|
||||
expect(script._type).toBe("script");
|
||||
expect(script.src).toBe("https://example.com/public/path/chunk2.js");
|
||||
expect(script.getAttribute("nonce")).toBe("nonce");
|
||||
expect(script.crossOrigin).toBe("anonymous");
|
||||
expect(script.onload).toBeTypeOf("function");
|
||||
|
||||
// Run the script
|
||||
__non_webpack_require__("./chunk2.js");
|
||||
|
||||
script.onload();
|
||||
|
||||
return promise3.then(() => {
|
||||
// Loading chunk2 again should not trigger prefetch/preload as it's already prefetch/preloaded
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// This config need to be set on initial evaluation to be effective
|
||||
__webpack_nonce__ = "nonce";
|
||||
__webpack_public_path__ = "https://example.com/public/path/";
|
||||
|
||||
it("should prefetch and preload child chunks on chunk load", () => {
|
||||
let link, script;
|
||||
|
||||
expect(document.head._children).toHaveLength(1);
|
||||
|
||||
// Test prefetch from entry chunk
|
||||
link = document.head._children[0];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1.js");
|
||||
|
||||
const promise = import(
|
||||
/* webpackChunkName: "chunk1", webpackPrefetch: true */ "./chunk1.js"
|
||||
);
|
||||
|
||||
expect(document.head._children).toHaveLength(3);
|
||||
|
||||
// Test normal script loading
|
||||
script = document.head._children[1];
|
||||
expect(script._type).toBe("script");
|
||||
expect(script.src).toBe("https://example.com/public/path/chunk1.js");
|
||||
expect(script.getAttribute("nonce")).toBe("nonce");
|
||||
expect(script.crossOrigin).toBe("anonymous");
|
||||
expect(script.onload).toBeTypeOf("function");
|
||||
|
||||
// Test preload of chunk1-b
|
||||
link = document.head._children[2];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("modulepreload");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-b.js");
|
||||
expect(link.charset).toBe("utf-8");
|
||||
expect(link.getAttribute("nonce")).toBe("nonce");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
// Run the script
|
||||
__non_webpack_require__("./chunk1.js");
|
||||
|
||||
script.onload();
|
||||
|
||||
return promise.then(() => {
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
|
||||
// Test prefetching for chunk1-c and chunk1-a in this order
|
||||
link = document.head._children[2];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-c.js");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
link = document.head._children[3];
|
||||
expect(link._type).toBe("link");
|
||||
expect(link.rel).toBe("prefetch");
|
||||
expect(link.href).toBe("https://example.com/public/path/chunk1-a.js");
|
||||
expect(link.crossOrigin).toBe("anonymous");
|
||||
|
||||
const promise2 = import(
|
||||
/* webpackChunkName: "chunk1", webpackPrefetch: true */ "./chunk1.js"
|
||||
);
|
||||
|
||||
// Loading chunk1 again should not trigger prefetch/preload
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
|
||||
const promise3 = import(/* webpackChunkName: "chunk2" */ "./chunk2.js");
|
||||
|
||||
expect(document.head._children).toHaveLength(5);
|
||||
|
||||
// Test normal script loading
|
||||
script = document.head._children[4];
|
||||
expect(script._type).toBe("script");
|
||||
expect(script.src).toBe("https://example.com/public/path/chunk2.js");
|
||||
expect(script.getAttribute("nonce")).toBe("nonce");
|
||||
expect(script.crossOrigin).toBe("anonymous");
|
||||
expect(script.onload).toBeTypeOf("function");
|
||||
|
||||
// Run the script
|
||||
__non_webpack_require__("./chunk2.js");
|
||||
|
||||
script.onload();
|
||||
|
||||
return promise3.then(() => {
|
||||
// Loading chunk2 again should not trigger prefetch/preload as it's already prefetch/preloaded
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
entry: "./index.mjs",
|
||||
experiments: {
|
||||
outputModule: true
|
||||
},
|
||||
name: "esm",
|
||||
target: "web",
|
||||
output: {
|
||||
publicPath: "",
|
||||
module: true,
|
||||
filename: "bundle0.js",
|
||||
chunkFilename: "[name].js",
|
||||
crossOriginLoading: "anonymous"
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
optimization: {
|
||||
minimize: false
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue