Adding option to set fetchPriority on script tags
This commit is contained in:
parent
5e3c4d0ddf
commit
f68ab55320
|
@ -81,6 +81,7 @@
|
|||
"eval",
|
||||
"Ewald",
|
||||
"exitance",
|
||||
"fetchpriority",
|
||||
"filebase",
|
||||
"fileoverview",
|
||||
"filepath",
|
||||
|
@ -104,8 +105,8 @@
|
|||
"hotupdatechunk",
|
||||
"ident",
|
||||
"idents",
|
||||
"IIFE's",
|
||||
"IIFE",
|
||||
"IIFE's",
|
||||
"informations",
|
||||
"instanceof",
|
||||
"inversed",
|
||||
|
@ -274,8 +275,8 @@
|
|||
"webassembly",
|
||||
"webassemblyjs",
|
||||
"webmake",
|
||||
"webpack's",
|
||||
"webpack",
|
||||
"webpack's",
|
||||
"Xarray",
|
||||
"Xexports",
|
||||
"Xfactory",
|
||||
|
|
|
@ -3005,6 +3005,10 @@ export interface JavascriptParserOptions {
|
|||
* Enable/disable parsing "import { createRequire } from "module"" and evaluating createRequire().
|
||||
*/
|
||||
createRequire?: boolean | string;
|
||||
/**
|
||||
* Specifies global fetchPriority for dynamic import.
|
||||
*/
|
||||
dynamicImportFetchPriority?: ("low" | "high" | "auto") | boolean;
|
||||
/**
|
||||
* Specifies global mode for dynamic import.
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ const {
|
|||
* @typedef {Object} RawChunkGroupOptions
|
||||
* @property {number=} preloadOrder
|
||||
* @property {number=} prefetchOrder
|
||||
* @property {string=} fetchPriority
|
||||
*/
|
||||
|
||||
/** @typedef {RawChunkGroupOptions & { name?: string }} ChunkGroupOptions */
|
||||
|
|
|
@ -936,14 +936,17 @@ class RuntimeTemplate {
|
|||
message,
|
||||
chunkName: block.chunkName
|
||||
});
|
||||
const fetchPriority = JSON.stringify(chunkGroup.options.fetchPriority);
|
||||
if (chunks.length === 1) {
|
||||
const chunkId = JSON.stringify(chunks[0].id);
|
||||
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
|
||||
return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId})`;
|
||||
return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}, ${fetchPriority})`;
|
||||
} else if (chunks.length > 0) {
|
||||
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
|
||||
const requireChunkId = chunk =>
|
||||
`${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)})`;
|
||||
`${RuntimeGlobals.ensureChunk}(${JSON.stringify(
|
||||
chunk.id
|
||||
)}, ${fetchPriority})`;
|
||||
return `Promise.all(${comment.trim()}[${chunks
|
||||
.map(requireChunkId)
|
||||
.join(", ")}])`;
|
||||
|
|
|
@ -47,10 +47,22 @@ class ImportParserPlugin {
|
|||
/** @type {RawChunkGroupOptions} */
|
||||
const groupOptions = {};
|
||||
|
||||
const { dynamicImportPreload, dynamicImportPrefetch } = this.options;
|
||||
const {
|
||||
dynamicImportPreload,
|
||||
dynamicImportPrefetch,
|
||||
dynamicImportFetchPriority
|
||||
} = this.options;
|
||||
if (dynamicImportPreload !== undefined && dynamicImportPreload !== false)
|
||||
groupOptions.preloadOrder =
|
||||
dynamicImportPreload === true ? 0 : dynamicImportPreload;
|
||||
if (
|
||||
dynamicImportFetchPriority !== undefined &&
|
||||
dynamicImportFetchPriority !== false
|
||||
)
|
||||
groupOptions.fetchPriority =
|
||||
dynamicImportFetchPriority === true
|
||||
? "auto"
|
||||
: dynamicImportFetchPriority;
|
||||
if (
|
||||
dynamicImportPrefetch !== undefined &&
|
||||
dynamicImportPrefetch !== false
|
||||
|
@ -141,6 +153,23 @@ class ImportParserPlugin {
|
|||
);
|
||||
}
|
||||
}
|
||||
if (importOptions.webpackFetchPriority !== undefined) {
|
||||
if (
|
||||
typeof importOptions.webpackFetchPriority !== "string" ||
|
||||
!["high", "low", "auto"].includes(
|
||||
importOptions.webpackFetchPriority
|
||||
)
|
||||
) {
|
||||
parser.state.module.addWarning(
|
||||
new UnsupportedFeatureWarning(
|
||||
`\`webpackFetchPriority\` expected "low", "high" or "auto", but received: ${importOptions.webpackFetchPriority}.`,
|
||||
expr.loc
|
||||
)
|
||||
);
|
||||
} else {
|
||||
groupOptions.fetchPriority = importOptions.webpackFetchPriority;
|
||||
}
|
||||
}
|
||||
if (importOptions.webpackInclude !== undefined) {
|
||||
if (
|
||||
!importOptions.webpackInclude ||
|
||||
|
|
|
@ -30,11 +30,14 @@ class EnsureChunkRuntimeModule extends RuntimeModule {
|
|||
"// This file contains only the entry chunk.",
|
||||
"// The chunk loading function for additional chunks",
|
||||
`${RuntimeGlobals.ensureChunk} = ${runtimeTemplate.basicFunction(
|
||||
"chunkId",
|
||||
"chunkId, fetchPriority",
|
||||
[
|
||||
`return Promise.all(Object.keys(${handlers}).reduce(${runtimeTemplate.basicFunction(
|
||||
"promises, key",
|
||||
[`${handlers}[key](chunkId, promises);`, "return promises;"]
|
||||
[
|
||||
`${handlers}[key](chunkId, promises, fetchPriority);`,
|
||||
"return promises;"
|
||||
]
|
||||
)}, []));`
|
||||
]
|
||||
)};`
|
||||
|
|
|
@ -81,6 +81,9 @@ class LoadScriptRuntimeModule extends HelperRuntimeModule {
|
|||
uniqueName
|
||||
? 'script.setAttribute("data-webpack", dataWebpackPrefix + key);'
|
||||
: "",
|
||||
"if(fetchPriority) {",
|
||||
Template.indent('script.setAttribute("fetchpriority", fetchPriority);'),
|
||||
"}",
|
||||
`script.src = ${
|
||||
this._withCreateScriptUrl
|
||||
? `${RuntimeGlobals.createScriptUrl}(url)`
|
||||
|
@ -105,53 +108,56 @@ class LoadScriptRuntimeModule extends HelperRuntimeModule {
|
|||
? `var dataWebpackPrefix = ${JSON.stringify(uniqueName + ":")};`
|
||||
: "// data-webpack is not used as build has no uniqueName",
|
||||
"// loadScript function to load a script via script tag",
|
||||
`${fn} = ${runtimeTemplate.basicFunction("url, done, key, chunkId", [
|
||||
"if(inProgress[url]) { inProgress[url].push(done); return; }",
|
||||
"var script, needAttach;",
|
||||
"if(key !== undefined) {",
|
||||
Template.indent([
|
||||
'var scripts = document.getElementsByTagName("script");',
|
||||
"for(var i = 0; i < scripts.length; i++) {",
|
||||
`${fn} = ${runtimeTemplate.basicFunction(
|
||||
"url, done, key, chunkId, fetchPriority",
|
||||
[
|
||||
"if(inProgress[url]) { inProgress[url].push(done); return; }",
|
||||
"var script, needAttach;",
|
||||
"if(key !== undefined) {",
|
||||
Template.indent([
|
||||
"var s = scripts[i];",
|
||||
`if(s.getAttribute("src") == url${
|
||||
uniqueName
|
||||
? ' || s.getAttribute("data-webpack") == dataWebpackPrefix + key'
|
||||
: ""
|
||||
}) { script = s; break; }`
|
||||
'var scripts = document.getElementsByTagName("script");',
|
||||
"for(var i = 0; i < scripts.length; i++) {",
|
||||
Template.indent([
|
||||
"var s = scripts[i];",
|
||||
`if(s.getAttribute("src") == url${
|
||||
uniqueName
|
||||
? ' || s.getAttribute("data-webpack") == dataWebpackPrefix + key'
|
||||
: ""
|
||||
}) { script = s; break; }`
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(!script) {",
|
||||
Template.indent([
|
||||
"needAttach = true;",
|
||||
createScript.call(code, this.chunk)
|
||||
]),
|
||||
"}",
|
||||
"inProgress[url] = [done];",
|
||||
"var onScriptComplete = " +
|
||||
runtimeTemplate.basicFunction(
|
||||
"prev, event",
|
||||
Template.asString([
|
||||
"// avoid mem leaks in IE.",
|
||||
"script.onerror = script.onload = null;",
|
||||
"clearTimeout(timeout);",
|
||||
"var doneFns = inProgress[url];",
|
||||
"delete inProgress[url];",
|
||||
"script.parentNode && script.parentNode.removeChild(script);",
|
||||
`doneFns && doneFns.forEach(${runtimeTemplate.returningFunction(
|
||||
"fn(event)",
|
||||
"fn"
|
||||
)});`,
|
||||
"if(prev) return prev(event);"
|
||||
])
|
||||
),
|
||||
`var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), ${loadTimeout});`,
|
||||
"script.onerror = onScriptComplete.bind(null, script.onerror);",
|
||||
"script.onload = onScriptComplete.bind(null, script.onload);",
|
||||
"needAttach && document.head.appendChild(script);"
|
||||
])};`
|
||||
"}",
|
||||
"if(!script) {",
|
||||
Template.indent([
|
||||
"needAttach = true;",
|
||||
createScript.call(code, this.chunk)
|
||||
]),
|
||||
"}",
|
||||
"inProgress[url] = [done];",
|
||||
"var onScriptComplete = " +
|
||||
runtimeTemplate.basicFunction(
|
||||
"prev, event",
|
||||
Template.asString([
|
||||
"// avoid mem leaks in IE.",
|
||||
"script.onerror = script.onload = null;",
|
||||
"clearTimeout(timeout);",
|
||||
"var doneFns = inProgress[url];",
|
||||
"delete inProgress[url];",
|
||||
"script.parentNode && script.parentNode.removeChild(script);",
|
||||
`doneFns && doneFns.forEach(${runtimeTemplate.returningFunction(
|
||||
"fn(event)",
|
||||
"fn"
|
||||
)});`,
|
||||
"if(prev) return prev(event);"
|
||||
])
|
||||
),
|
||||
`var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), ${loadTimeout});`,
|
||||
"script.onerror = onScriptComplete.bind(null, script.onerror);",
|
||||
"script.onload = onScriptComplete.bind(null, script.onload);",
|
||||
"needAttach && document.head.appendChild(script);"
|
||||
]
|
||||
)};`
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
withLoading
|
||||
? Template.asString([
|
||||
`${fn}.j = ${runtimeTemplate.basicFunction(
|
||||
"chunkId, promises",
|
||||
"chunkId, promises, fetchPriority",
|
||||
hasJsMatcher !== false
|
||||
? Template.indent([
|
||||
"// JSONP chunk loading for javascript",
|
||||
|
@ -190,7 +190,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
"}"
|
||||
]
|
||||
)};`,
|
||||
`${RuntimeGlobals.loadScript}(url, loadingEnded, "chunk-" + chunkId, chunkId);`
|
||||
`${RuntimeGlobals.loadScript}(url, loadingEnded, "chunk-" + chunkId, chunkId, fetchPriority);`
|
||||
]),
|
||||
hasJsMatcher === true
|
||||
? "}"
|
||||
|
|
|
@ -1632,6 +1632,17 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"dynamicImportFetchPriority": {
|
||||
"description": "Specifies global fetchPriority for dynamic import.",
|
||||
"anyOf": [
|
||||
{
|
||||
"enum": ["low", "high", "auto"]
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dynamicImportMode": {
|
||||
"description": "Specifies global mode for dynamic import.",
|
||||
"enum": ["eager", "weak", "lazy", "lazy-once"]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export default "a";
|
|
@ -0,0 +1 @@
|
|||
export default "b";
|
|
@ -0,0 +1 @@
|
|||
export default "c";
|
|
@ -180,6 +180,13 @@ if (process.env.NODE_ENV === "production") {
|
|||
}
|
||||
);
|
||||
});
|
||||
it("should be able to load with webpackFetchPriorty high, low and auto", function () {
|
||||
return Promise.all([
|
||||
import(/* webpackFetchPriority: "high"*/ "./dir14/a"),
|
||||
import(/* webpackFetchPriority: "low"*/ "./dir14/b"),
|
||||
import(/* webpackFetchPriority: "auto"*/ "./dir14/c"),
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
function testChunkLoading(load, expectedSyncInitial, expectedSyncRequested) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export default "a";
|
|
@ -0,0 +1,3 @@
|
|||
import * as shared from './shared';
|
||||
console.log(shared);
|
||||
export default "b";
|
|
@ -0,0 +1,3 @@
|
|||
import * as shared from './shared';
|
||||
console.log(shared);
|
||||
export default "b";
|
|
@ -0,0 +1 @@
|
|||
export default "c";
|
|
@ -0,0 +1 @@
|
|||
export default "d";
|
|
@ -0,0 +1,31 @@
|
|||
it("should set fetchPriority", () => {
|
||||
// Single Chunk
|
||||
import(/* webpackFetchPriority: "high" */ "./a");
|
||||
expect(document.head._children).toHaveLength(1);
|
||||
const script1 = document.head._children[0];
|
||||
expect(script1._attributes.fetchpriority).toBe("high");
|
||||
|
||||
// Multiple Chunks
|
||||
import(/* webpackFetchPriority: "high" */ "./b");
|
||||
import(/* webpackFetchPriority: "high" */ "./b2");
|
||||
expect(document.head._children).toHaveLength(4);
|
||||
const script2 = document.head._children[1];
|
||||
const script3 = document.head._children[2];
|
||||
const script4 = document.head._children[3];
|
||||
expect(script2._attributes.fetchpriority).toBe("high");
|
||||
expect(script3._attributes.fetchpriority).toBe("high");
|
||||
expect(script4._attributes.fetchpriority).toBe("high");
|
||||
|
||||
// Single Chunk, low
|
||||
import(/* webpackFetchPriority: "low" */ "./c");
|
||||
expect(document.head._children).toHaveLength(5);
|
||||
const script5 = document.head._children[4];
|
||||
expect(script5._attributes.fetchpriority).toBe("low");
|
||||
|
||||
// Single Chunk, auto
|
||||
import(/* webpackFetchPriority: "auto" */ "./d");
|
||||
expect(document.head._children).toHaveLength(6);
|
||||
const script6 = document.head._children[5];
|
||||
expect(script6._attributes.fetchpriority).toBe("auto");
|
||||
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
export default "shared";
|
|
@ -0,0 +1,14 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: "web",
|
||||
output: {
|
||||
chunkFilename: "[name].js",
|
||||
crossOriginLoading: "anonymous"
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
splitChunks: {
|
||||
minSize: 1
|
||||
}
|
||||
}
|
||||
};
|
|
@ -6013,6 +6013,11 @@ declare interface JavascriptParserOptions {
|
|||
*/
|
||||
createRequire?: string | boolean;
|
||||
|
||||
/**
|
||||
* Specifies global fetchPriority for dynamic import.
|
||||
*/
|
||||
dynamicImportFetchPriority?: boolean | "auto" | "low" | "high";
|
||||
|
||||
/**
|
||||
* Specifies global mode for dynamic import.
|
||||
*/
|
||||
|
@ -9900,6 +9905,7 @@ declare interface ProvidesObject {
|
|||
declare interface RawChunkGroupOptions {
|
||||
preloadOrder?: number;
|
||||
prefetchOrder?: number;
|
||||
fetchPriority?: string;
|
||||
}
|
||||
type RawLoaderDefinition<
|
||||
OptionsType = {},
|
||||
|
|
Loading…
Reference in New Issue