first commit

This commit is contained in:
monjack
2025-06-20 18:01:48 +08:00
commit 6daa6d65c1
24611 changed files with 2512443 additions and 0 deletions

View File

@ -0,0 +1,133 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class AsyncModuleRuntimeModule extends HelperRuntimeModule {
constructor() {
super("async module");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
const fn = RuntimeGlobals.asyncModule;
return Template.asString([
'var webpackQueues = typeof Symbol === "function" ? Symbol("webpack queues") : "__webpack_queues__";',
`var webpackExports = typeof Symbol === "function" ? Symbol("webpack exports") : "${RuntimeGlobals.exports}";`,
'var webpackError = typeof Symbol === "function" ? Symbol("webpack error") : "__webpack_error__";',
`var resolveQueue = ${runtimeTemplate.basicFunction("queue", [
"if(queue && queue.d < 1) {",
Template.indent([
"queue.d = 1;",
`queue.forEach(${runtimeTemplate.expressionFunction(
"fn.r--",
"fn"
)});`,
`queue.forEach(${runtimeTemplate.expressionFunction(
"fn.r-- ? fn.r++ : fn()",
"fn"
)});`
]),
"}"
])}`,
`var wrapDeps = ${runtimeTemplate.returningFunction(
`deps.map(${runtimeTemplate.basicFunction("dep", [
'if(dep !== null && typeof dep === "object") {',
Template.indent([
"if(dep[webpackQueues]) return dep;",
"if(dep.then) {",
Template.indent([
"var queue = [];",
"queue.d = 0;",
`dep.then(${runtimeTemplate.basicFunction("r", [
"obj[webpackExports] = r;",
"resolveQueue(queue);"
])}, ${runtimeTemplate.basicFunction("e", [
"obj[webpackError] = e;",
"resolveQueue(queue);"
])});`,
"var obj = {};",
`obj[webpackQueues] = ${runtimeTemplate.expressionFunction(
"fn(queue)",
"fn"
)};`,
"return obj;"
]),
"}"
]),
"}",
"var ret = {};",
`ret[webpackQueues] = ${runtimeTemplate.emptyFunction()};`,
"ret[webpackExports] = dep;",
"return ret;"
])})`,
"deps"
)};`,
`${fn} = ${runtimeTemplate.basicFunction("module, body, hasAwait", [
"var queue;",
"hasAwait && ((queue = []).d = -1);",
"var depQueues = new Set();",
"var exports = module.exports;",
"var currentDeps;",
"var outerResolve;",
"var reject;",
`var promise = new Promise(${runtimeTemplate.basicFunction(
"resolve, rej",
["reject = rej;", "outerResolve = resolve;"]
)});`,
"promise[webpackExports] = exports;",
`promise[webpackQueues] = ${runtimeTemplate.expressionFunction(
`queue && fn(queue), depQueues.forEach(fn), promise["catch"](${runtimeTemplate.emptyFunction()})`,
"fn"
)};`,
"module.exports = promise;",
`body(${runtimeTemplate.basicFunction("deps", [
"currentDeps = wrapDeps(deps);",
"var fn;",
`var getResult = ${runtimeTemplate.returningFunction(
`currentDeps.map(${runtimeTemplate.basicFunction("d", [
"if(d[webpackError]) throw d[webpackError];",
"return d[webpackExports];"
])})`
)}`,
`var promise = new Promise(${runtimeTemplate.basicFunction(
"resolve",
[
`fn = ${runtimeTemplate.expressionFunction(
"resolve(getResult)",
""
)};`,
"fn.r = 0;",
`var fnQueue = ${runtimeTemplate.expressionFunction(
"q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn)))",
"q"
)};`,
`currentDeps.map(${runtimeTemplate.expressionFunction(
"dep[webpackQueues](fnQueue)",
"dep"
)});`
]
)});`,
"return fn.r ? promise : getResult();"
])}, ${runtimeTemplate.expressionFunction(
"(err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)",
"err"
)});`,
"queue && queue.d < 0 && (queue.d = 0);"
])};`
]);
}
}
module.exports = AsyncModuleRuntimeModule;

View File

@ -0,0 +1,85 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
const { getUndoPath } = require("../util/identifier");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compilation")} Compilation */
class AutoPublicPathRuntimeModule extends RuntimeModule {
constructor() {
super("publicPath", RuntimeModule.STAGE_BASIC);
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { scriptType, importMetaName, path } = compilation.outputOptions;
const chunkName = compilation.getPath(
JavascriptModulesPlugin.getChunkFilenameTemplate(
/** @type {Chunk} */
(this.chunk),
compilation.outputOptions
),
{
chunk: this.chunk,
contentHashType: "javascript"
}
);
const undoPath = getUndoPath(
chunkName,
/** @type {string} */ (path),
false
);
return Template.asString([
"var scriptUrl;",
scriptType === "module"
? `if (typeof ${importMetaName}.url === "string") scriptUrl = ${importMetaName}.url`
: Template.asString([
`if (${RuntimeGlobals.global}.importScripts) scriptUrl = ${RuntimeGlobals.global}.location + "";`,
`var document = ${RuntimeGlobals.global}.document;`,
"if (!scriptUrl && document) {",
Template.indent([
// Technically we could use `document.currentScript instanceof window.HTMLScriptElement`,
// but an attacker could try to inject `<script>HTMLScriptElement = HTMLImageElement</script>`
// and use `<img name="currentScript" src="https://attacker.controlled.server/"></img>`
"if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT')",
Template.indent("scriptUrl = document.currentScript.src;"),
"if (!scriptUrl) {",
Template.indent([
'var scripts = document.getElementsByTagName("script");',
"if(scripts.length) {",
Template.indent([
"var i = scripts.length - 1;",
"while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;"
]),
"}"
]),
"}"
]),
"}"
]),
"// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration",
'// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.',
'if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");',
'scriptUrl = scriptUrl.replace(/^blob:/, "").replace(/#.*$/, "").replace(/\\?.*$/, "").replace(/\\/[^\\/]+$/, "/");',
!undoPath
? `${RuntimeGlobals.publicPath} = scriptUrl;`
: `${RuntimeGlobals.publicPath} = scriptUrl + ${JSON.stringify(
undoPath
)};`
]);
}
}
module.exports = AutoPublicPathRuntimeModule;

View File

@ -0,0 +1,35 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescriptionNormalized */
/** @typedef {import("../Chunk")} Chunk */
class BaseUriRuntimeModule extends RuntimeModule {
constructor() {
super("base uri", RuntimeModule.STAGE_ATTACH);
}
/**
* @returns {string | null} runtime code
*/
generate() {
const chunk = /** @type {Chunk} */ (this.chunk);
const options =
/** @type {EntryDescriptionNormalized} */
(chunk.getEntryOptions());
return `${RuntimeGlobals.baseURI} = ${
options.baseUri === undefined
? "undefined"
: JSON.stringify(options.baseUri)
};`;
}
}
module.exports = BaseUriRuntimeModule;

View File

@ -0,0 +1,27 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
class ChunkNameRuntimeModule extends RuntimeModule {
/**
* @param {string} chunkName the chunk's name
*/
constructor(chunkName) {
super("chunkName");
this.chunkName = chunkName;
}
/**
* @returns {string | null} runtime code
*/
generate() {
return `${RuntimeGlobals.chunkName} = ${JSON.stringify(this.chunkName)};`;
}
}
module.exports = ChunkNameRuntimeModule;

View File

@ -0,0 +1,40 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class CompatGetDefaultExportRuntimeModule extends HelperRuntimeModule {
constructor() {
super("compat get default export");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
const fn = RuntimeGlobals.compatGetDefaultExport;
return Template.asString([
"// getDefaultExport function for compatibility with non-harmony modules",
`${fn} = ${runtimeTemplate.basicFunction("module", [
"var getter = module && module.__esModule ?",
Template.indent([
`${runtimeTemplate.returningFunction("module['default']")} :`,
`${runtimeTemplate.returningFunction("module")};`
]),
`${RuntimeGlobals.definePropertyGetters}(getter, { a: getter });`,
"return getter;"
])};`
]);
}
}
module.exports = CompatGetDefaultExportRuntimeModule;

View File

@ -0,0 +1,83 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../MainTemplate")} MainTemplate */
class CompatRuntimeModule extends RuntimeModule {
constructor() {
super("compat", RuntimeModule.STAGE_ATTACH);
this.fullHash = true;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const chunk = /** @type {Chunk} */ (this.chunk);
const {
runtimeTemplate,
mainTemplate,
moduleTemplates,
dependencyTemplates
} = compilation;
const bootstrap = mainTemplate.hooks.bootstrap.call(
"",
chunk,
compilation.hash || "XXXX",
moduleTemplates.javascript,
dependencyTemplates
);
const localVars = mainTemplate.hooks.localVars.call(
"",
chunk,
compilation.hash || "XXXX"
);
const requireExtensions = mainTemplate.hooks.requireExtensions.call(
"",
chunk,
compilation.hash || "XXXX"
);
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
let requireEnsure = "";
if (runtimeRequirements.has(RuntimeGlobals.ensureChunk)) {
const requireEnsureHandler = mainTemplate.hooks.requireEnsure.call(
"",
chunk,
compilation.hash || "XXXX",
"chunkId"
);
if (requireEnsureHandler) {
requireEnsure = `${
RuntimeGlobals.ensureChunkHandlers
}.compat = ${runtimeTemplate.basicFunction(
"chunkId, promises",
requireEnsureHandler
)};`;
}
}
return [bootstrap, localVars, requireEnsure, requireExtensions]
.filter(Boolean)
.join("\n");
}
/**
* @returns {boolean} true, if the runtime module should get it's own scope
*/
shouldIsolate() {
// We avoid isolating this to have better backward-compat
return false;
}
}
module.exports = CompatRuntimeModule;

View File

@ -0,0 +1,69 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class CreateFakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
constructor() {
super("create fake namespace object");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
const fn = RuntimeGlobals.createFakeNamespaceObject;
return Template.asString([
`var getProto = Object.getPrototypeOf ? ${runtimeTemplate.returningFunction(
"Object.getPrototypeOf(obj)",
"obj"
)} : ${runtimeTemplate.returningFunction("obj.__proto__", "obj")};`,
"var leafPrototypes;",
"// create a fake namespace object",
"// mode & 1: value is a module id, require it",
"// mode & 2: merge all properties of value into the ns",
"// mode & 4: return value when already ns object",
"// mode & 16: return value when it's Promise-like",
"// mode & 8|1: behave like require",
// Note: must be a function (not arrow), because this is used in body!
`${fn} = function(value, mode) {`,
Template.indent([
"if(mode & 1) value = this(value);",
"if(mode & 8) return value;",
"if(typeof value === 'object' && value) {",
Template.indent([
"if((mode & 4) && value.__esModule) return value;",
"if((mode & 16) && typeof value.then === 'function') return value;"
]),
"}",
"var ns = Object.create(null);",
`${RuntimeGlobals.makeNamespaceObject}(ns);`,
"var def = {};",
"leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];",
"for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {",
Template.indent([
`Object.getOwnPropertyNames(current).forEach(${runtimeTemplate.expressionFunction(
`def[key] = ${runtimeTemplate.returningFunction("value[key]", "")}`,
"key"
)});`
]),
"}",
`def['default'] = ${runtimeTemplate.returningFunction("value", "")};`,
`${RuntimeGlobals.definePropertyGetters}(ns, def);`,
"return ns;"
]),
"};"
]);
}
}
module.exports = CreateFakeNamespaceObjectRuntimeModule;

View File

@ -0,0 +1,38 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class CreateScriptRuntimeModule extends HelperRuntimeModule {
constructor() {
super("trusted types script");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate, outputOptions } = compilation;
const { trustedTypes } = outputOptions;
const fn = RuntimeGlobals.createScript;
return Template.asString(
`${fn} = ${runtimeTemplate.returningFunction(
trustedTypes
? `${RuntimeGlobals.getTrustedTypesPolicy}().createScript(script)`
: "script",
"script"
)};`
);
}
}
module.exports = CreateScriptRuntimeModule;

View File

@ -0,0 +1,38 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class CreateScriptUrlRuntimeModule extends HelperRuntimeModule {
constructor() {
super("trusted types script url");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate, outputOptions } = compilation;
const { trustedTypes } = outputOptions;
const fn = RuntimeGlobals.createScriptUrl;
return Template.asString(
`${fn} = ${runtimeTemplate.returningFunction(
trustedTypes
? `${RuntimeGlobals.getTrustedTypesPolicy}().createScriptURL(url)`
: "url",
"url"
)};`
);
}
}
module.exports = CreateScriptUrlRuntimeModule;

View File

@ -0,0 +1,42 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class DefinePropertyGettersRuntimeModule extends HelperRuntimeModule {
constructor() {
super("define property getters");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
const fn = RuntimeGlobals.definePropertyGetters;
return Template.asString([
"// define getter functions for harmony exports",
`${fn} = ${runtimeTemplate.basicFunction("exports, definition", [
"for(var key in definition) {",
Template.indent([
`if(${RuntimeGlobals.hasOwnProperty}(definition, key) && !${RuntimeGlobals.hasOwnProperty}(exports, key)) {`,
Template.indent([
"Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });"
]),
"}"
]),
"}"
])};`
]);
}
}
module.exports = DefinePropertyGettersRuntimeModule;

View File

@ -0,0 +1,68 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
class EnsureChunkRuntimeModule extends RuntimeModule {
/**
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
*/
constructor(runtimeRequirements) {
super("ensure chunk");
this.runtimeRequirements = runtimeRequirements;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
// Check if there are non initial chunks which need to be imported using require-ensure
if (this.runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)) {
const withFetchPriority = this.runtimeRequirements.has(
RuntimeGlobals.hasFetchPriority
);
const handlers = RuntimeGlobals.ensureChunkHandlers;
return Template.asString([
`${handlers} = {};`,
"// This file contains only the entry chunk.",
"// The chunk loading function for additional chunks",
`${RuntimeGlobals.ensureChunk} = ${runtimeTemplate.basicFunction(
`chunkId${withFetchPriority ? ", fetchPriority" : ""}`,
[
`return Promise.all(Object.keys(${handlers}).reduce(${runtimeTemplate.basicFunction(
"promises, key",
[
`${handlers}[key](chunkId, promises${
withFetchPriority ? ", fetchPriority" : ""
});`,
"return promises;"
]
)}, []));`
]
)};`
]);
}
// There ensureChunk is used somewhere in the tree, so we need an empty requireEnsure
// function. This can happen with multiple entrypoints.
return Template.asString([
"// The chunk loading function for additional chunks",
"// Since all referenced chunks are already included",
"// in this file, this function is empty here.",
`${RuntimeGlobals.ensureChunk} = ${runtimeTemplate.returningFunction(
"Promise.resolve()"
)};`
]);
}
}
module.exports = EnsureChunkRuntimeModule;

View File

@ -0,0 +1,294 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const { first } = require("../util/SetHelpers");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Chunk").ChunkId} ChunkId */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
/** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
class GetChunkFilenameRuntimeModule extends RuntimeModule {
/**
* @param {string} contentType the contentType to use the content hash for
* @param {string} name kind of filename
* @param {string} global function name to be assigned
* @param {(chunk: Chunk) => TemplatePath | false} getFilenameForChunk functor to get the filename or function
* @param {boolean} allChunks when false, only async chunks are included
*/
constructor(contentType, name, global, getFilenameForChunk, allChunks) {
super(`get ${name} chunk filename`);
this.contentType = contentType;
this.global = global;
this.getFilenameForChunk = getFilenameForChunk;
this.allChunks = allChunks;
this.dependentHash = true;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const { global, contentType, getFilenameForChunk, allChunks } = this;
const compilation = /** @type {Compilation} */ (this.compilation);
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const chunk = /** @type {Chunk} */ (this.chunk);
const { runtimeTemplate } = compilation;
/** @type {Map<string | TemplatePath, Set<Chunk>>} */
const chunkFilenames = new Map();
let maxChunks = 0;
/** @type {string | undefined} */
let dynamicFilename;
/**
* @param {Chunk} c the chunk
* @returns {void}
*/
const addChunk = c => {
const chunkFilename = getFilenameForChunk(c);
if (chunkFilename) {
let set = chunkFilenames.get(chunkFilename);
if (set === undefined) {
chunkFilenames.set(chunkFilename, (set = new Set()));
}
set.add(c);
if (typeof chunkFilename === "string") {
if (set.size < maxChunks) return;
if (set.size === maxChunks) {
if (
chunkFilename.length <
/** @type {string} */ (dynamicFilename).length
) {
return;
}
if (
chunkFilename.length ===
/** @type {string} */ (dynamicFilename).length &&
chunkFilename < /** @type {string} */ (dynamicFilename)
) {
return;
}
}
maxChunks = set.size;
dynamicFilename = chunkFilename;
}
}
};
/** @type {string[]} */
const includedChunksMessages = [];
if (allChunks) {
includedChunksMessages.push("all chunks");
for (const c of chunk.getAllReferencedChunks()) {
addChunk(c);
}
} else {
includedChunksMessages.push("async chunks");
for (const c of chunk.getAllAsyncChunks()) {
addChunk(c);
}
const includeEntries = chunkGraph
.getTreeRuntimeRequirements(chunk)
.has(RuntimeGlobals.ensureChunkIncludeEntries);
if (includeEntries) {
includedChunksMessages.push("sibling chunks for the entrypoint");
for (const c of chunkGraph.getChunkEntryDependentChunksIterable(
chunk
)) {
addChunk(c);
}
}
}
for (const entrypoint of chunk.getAllReferencedAsyncEntrypoints()) {
addChunk(entrypoint.chunks[entrypoint.chunks.length - 1]);
}
/** @type {Map<string, Set<string | number | null>>} */
const staticUrls = new Map();
/** @type {Set<Chunk>} */
const dynamicUrlChunks = new Set();
/**
* @param {Chunk} c the chunk
* @param {string | TemplatePath} chunkFilename the filename template for the chunk
* @returns {void}
*/
const addStaticUrl = (c, chunkFilename) => {
/**
* @param {string | number} value a value
* @returns {string} string to put in quotes
*/
const unquotedStringify = value => {
const str = `${value}`;
if (str.length >= 5 && str === `${c.id}`) {
// This is shorter and generates the same result
return '" + chunkId + "';
}
const s = JSON.stringify(str);
return s.slice(1, -1);
};
/**
* @param {string} value string
* @returns {(length: number) => string} string to put in quotes with length
*/
const unquotedStringifyWithLength = value => length =>
unquotedStringify(`${value}`.slice(0, length));
const chunkFilenameValue =
typeof chunkFilename === "function"
? JSON.stringify(
chunkFilename({
chunk: c,
contentHashType: contentType
})
)
: JSON.stringify(chunkFilename);
const staticChunkFilename = compilation.getPath(chunkFilenameValue, {
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
hashWithLength: length =>
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
chunk: {
id: unquotedStringify(/** @type {ChunkId} */ (c.id)),
hash: unquotedStringify(/** @type {string} */ (c.renderedHash)),
hashWithLength: unquotedStringifyWithLength(
/** @type {string} */ (c.renderedHash)
),
name: unquotedStringify(c.name || /** @type {ChunkId} */ (c.id)),
contentHash: {
[contentType]: unquotedStringify(c.contentHash[contentType])
},
contentHashWithLength: {
[contentType]: unquotedStringifyWithLength(
c.contentHash[contentType]
)
}
},
contentHashType: contentType
});
let set = staticUrls.get(staticChunkFilename);
if (set === undefined) {
staticUrls.set(staticChunkFilename, (set = new Set()));
}
set.add(c.id);
};
for (const [filename, chunks] of chunkFilenames) {
if (filename !== dynamicFilename) {
for (const c of chunks) addStaticUrl(c, filename);
} else {
for (const c of chunks) dynamicUrlChunks.add(c);
}
}
/**
* @param {(chunk: Chunk) => string | number} fn function from chunk to value
* @returns {string} code with static mapping of results of fn
*/
const createMap = fn => {
/** @type {Record<number | string, number | string>} */
const obj = {};
let useId = false;
/** @type {number | string | undefined} */
let lastKey;
let entries = 0;
for (const c of dynamicUrlChunks) {
const value = fn(c);
if (value === c.id) {
useId = true;
} else {
obj[/** @type {number | string} */ (c.id)] = value;
lastKey = /** @type {number | string} */ (c.id);
entries++;
}
}
if (entries === 0) return "chunkId";
if (entries === 1) {
return useId
? `(chunkId === ${JSON.stringify(lastKey)} ? ${JSON.stringify(
obj[/** @type {number | string} */ (lastKey)]
)} : chunkId)`
: JSON.stringify(obj[/** @type {number | string} */ (lastKey)]);
}
return useId
? `(${JSON.stringify(obj)}[chunkId] || chunkId)`
: `${JSON.stringify(obj)}[chunkId]`;
};
/**
* @param {(chunk: Chunk) => string | number} fn function from chunk to value
* @returns {string} code with static mapping of results of fn for including in quoted string
*/
const mapExpr = fn => `" + ${createMap(fn)} + "`;
/**
* @param {(chunk: Chunk) => string | number} fn function from chunk to value
* @returns {(length: number) => string} function which generates code with static mapping of results of fn for including in quoted string for specific length
*/
const mapExprWithLength = fn => length =>
`" + ${createMap(c => `${fn(c)}`.slice(0, length))} + "`;
const url =
dynamicFilename &&
compilation.getPath(JSON.stringify(dynamicFilename), {
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
hashWithLength: length =>
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
chunk: {
id: '" + chunkId + "',
hash: mapExpr(c => /** @type {string} */ (c.renderedHash)),
hashWithLength: mapExprWithLength(
c => /** @type {string} */ (c.renderedHash)
),
name: mapExpr(c => c.name || /** @type {number | string} */ (c.id)),
contentHash: {
[contentType]: mapExpr(c => c.contentHash[contentType])
},
contentHashWithLength: {
[contentType]: mapExprWithLength(c => c.contentHash[contentType])
}
},
contentHashType: contentType
});
return Template.asString([
`// This function allow to reference ${includedChunksMessages.join(
" and "
)}`,
`${global} = ${runtimeTemplate.basicFunction(
"chunkId",
staticUrls.size > 0
? [
"// return url for filenames not based on template",
// it minimizes to `x===1?"...":x===2?"...":"..."`
Template.asString(
Array.from(staticUrls, ([url, ids]) => {
const condition =
ids.size === 1
? `chunkId === ${JSON.stringify(first(ids))}`
: `{${Array.from(
ids,
id => `${JSON.stringify(id)}:1`
).join(",")}}[chunkId]`;
return `if (${condition}) return ${url};`;
})
),
"// return url for filenames based on template",
`return ${url};`
]
: ["// return url for filenames based on template", `return ${url};`]
)};`
]);
}
}
module.exports = GetChunkFilenameRuntimeModule;

View File

@ -0,0 +1,30 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class GetFullHashRuntimeModule extends RuntimeModule {
constructor() {
super("getFullHash");
this.fullHash = true;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return `${RuntimeGlobals.getFullHash} = ${runtimeTemplate.returningFunction(
JSON.stringify(compilation.hash || "XXXX")
)}`;
}
}
module.exports = GetFullHashRuntimeModule;

View File

@ -0,0 +1,47 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compilation")} Compilation */
class GetMainFilenameRuntimeModule extends RuntimeModule {
/**
* @param {string} name readable name
* @param {string} global global object binding
* @param {string} filename main file name
*/
constructor(name, global, filename) {
super(`get ${name} filename`);
this.global = global;
this.filename = filename;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const { global, filename } = this;
const compilation = /** @type {Compilation} */ (this.compilation);
const chunk = /** @type {Chunk} */ (this.chunk);
const { runtimeTemplate } = compilation;
const url = compilation.getPath(JSON.stringify(filename), {
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
hashWithLength: length =>
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
chunk,
runtime: chunk.runtime
});
return Template.asString([
`${global} = ${runtimeTemplate.returningFunction(url)};`
]);
}
}
module.exports = GetMainFilenameRuntimeModule;

View File

@ -0,0 +1,98 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
class GetTrustedTypesPolicyRuntimeModule extends HelperRuntimeModule {
/**
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
*/
constructor(runtimeRequirements) {
super("trusted types policy");
this.runtimeRequirements = runtimeRequirements;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate, outputOptions } = compilation;
const { trustedTypes } = outputOptions;
const fn = RuntimeGlobals.getTrustedTypesPolicy;
const wrapPolicyCreationInTryCatch = trustedTypes
? trustedTypes.onPolicyCreationFailure === "continue"
: false;
return Template.asString([
"var policy;",
`${fn} = ${runtimeTemplate.basicFunction("", [
"// Create Trusted Type policy if Trusted Types are available and the policy doesn't exist yet.",
"if (policy === undefined) {",
Template.indent([
"policy = {",
Template.indent(
[
...(this.runtimeRequirements.has(RuntimeGlobals.createScript)
? [
`createScript: ${runtimeTemplate.returningFunction(
"script",
"script"
)}`
]
: []),
...(this.runtimeRequirements.has(RuntimeGlobals.createScriptUrl)
? [
`createScriptURL: ${runtimeTemplate.returningFunction(
"url",
"url"
)}`
]
: [])
].join(",\n")
),
"};",
...(trustedTypes
? [
'if (typeof trustedTypes !== "undefined" && trustedTypes.createPolicy) {',
Template.indent([
...(wrapPolicyCreationInTryCatch ? ["try {"] : []),
...[
`policy = trustedTypes.createPolicy(${JSON.stringify(
trustedTypes.policyName
)}, policy);`
].map(line =>
wrapPolicyCreationInTryCatch ? Template.indent(line) : line
),
...(wrapPolicyCreationInTryCatch
? [
"} catch (e) {",
Template.indent([
`console.warn('Could not create trusted-types policy ${JSON.stringify(
trustedTypes.policyName
)}');`
]),
"}"
]
: [])
]),
"}"
]
: [])
]),
"}",
"return policy;"
])};`
]);
}
}
module.exports = GetTrustedTypesPolicyRuntimeModule;

View File

@ -0,0 +1,47 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
class GlobalRuntimeModule extends RuntimeModule {
constructor() {
super("global");
}
/**
* @returns {string | null} runtime code
*/
generate() {
return Template.asString([
`${RuntimeGlobals.global} = (function() {`,
Template.indent([
"if (typeof globalThis === 'object') return globalThis;",
"try {",
Template.indent(
// This works in non-strict mode
// or
// This works if eval is allowed (see CSP)
"return this || new Function('return this')();"
),
"} catch (e) {",
Template.indent(
// This works if the window reference is available
"if (typeof window === 'object') return window;"
),
"}"
// It can still be `undefined`, but nothing to do about it...
// We return `undefined`, instead of nothing here, so it's
// easier to handle this case:
// if (!global) { … }
]),
"})();"
]);
}
}
module.exports = GlobalRuntimeModule;

View File

@ -0,0 +1,35 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Sergey Melyukov @smelukov
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Compilation")} Compilation */
class HasOwnPropertyRuntimeModule extends RuntimeModule {
constructor() {
super("hasOwnProperty shorthand");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return Template.asString([
`${RuntimeGlobals.hasOwnProperty} = ${runtimeTemplate.returningFunction(
"Object.prototype.hasOwnProperty.call(obj, prop)",
"obj, prop"
)}`
]);
}
}
module.exports = HasOwnPropertyRuntimeModule;

View File

@ -0,0 +1,18 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeModule = require("../RuntimeModule");
class HelperRuntimeModule extends RuntimeModule {
/**
* @param {string} name a readable name
*/
constructor(name) {
super(name);
}
}
module.exports = HelperRuntimeModule;

View File

@ -0,0 +1,174 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const { SyncWaterfallHook } = require("tapable");
const Compilation = require("../Compilation");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/**
* @typedef {object} LoadScriptCompilationHooks
* @property {SyncWaterfallHook<[string, Chunk]>} createScript
*/
/** @type {WeakMap<Compilation, LoadScriptCompilationHooks>} */
const compilationHooksMap = new WeakMap();
class LoadScriptRuntimeModule extends HelperRuntimeModule {
/**
* @param {Compilation} compilation the compilation
* @returns {LoadScriptCompilationHooks} hooks
*/
static getCompilationHooks(compilation) {
if (!(compilation instanceof Compilation)) {
throw new TypeError(
"The 'compilation' argument must be an instance of Compilation"
);
}
let hooks = compilationHooksMap.get(compilation);
if (hooks === undefined) {
hooks = {
createScript: new SyncWaterfallHook(["source", "chunk"])
};
compilationHooksMap.set(compilation, hooks);
}
return hooks;
}
/**
* @param {boolean=} withCreateScriptUrl use create script url for trusted types
* @param {boolean=} withFetchPriority use `fetchPriority` attribute
*/
constructor(withCreateScriptUrl, withFetchPriority) {
super("load script");
this._withCreateScriptUrl = withCreateScriptUrl;
this._withFetchPriority = withFetchPriority;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate, outputOptions } = compilation;
const {
scriptType,
chunkLoadTimeout: loadTimeout,
crossOriginLoading,
uniqueName,
charset
} = outputOptions;
const fn = RuntimeGlobals.loadScript;
const { createScript } =
LoadScriptRuntimeModule.getCompilationHooks(compilation);
const code = Template.asString([
"script = document.createElement('script');",
scriptType ? `script.type = ${JSON.stringify(scriptType)};` : "",
charset ? "script.charset = 'utf-8';" : "",
`script.timeout = ${/** @type {number} */ (loadTimeout) / 1000};`,
`if (${RuntimeGlobals.scriptNonce}) {`,
Template.indent(
`script.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
),
"}",
uniqueName
? 'script.setAttribute("data-webpack", dataWebpackPrefix + key);'
: "",
this._withFetchPriority
? Template.asString([
"if(fetchPriority) {",
Template.indent(
'script.setAttribute("fetchpriority", fetchPriority);'
),
"}"
])
: "",
`script.src = ${
this._withCreateScriptUrl
? `${RuntimeGlobals.createScriptUrl}(url)`
: "url"
};`,
crossOriginLoading
? crossOriginLoading === "use-credentials"
? 'script.crossOrigin = "use-credentials";'
: Template.asString([
"if (script.src.indexOf(window.location.origin + '/') !== 0) {",
Template.indent(
`script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
),
"}"
])
: ""
]);
return Template.asString([
"var inProgress = {};",
uniqueName
? `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${
this._withFetchPriority ? ", fetchPriority" : ""
}`,
[
"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++) {",
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, /** @type {Chunk} */ (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);"
]
)};`
]);
}
}
module.exports = LoadScriptRuntimeModule;

View File

@ -0,0 +1,39 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class MakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
constructor() {
super("make namespace object");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
const fn = RuntimeGlobals.makeNamespaceObject;
return Template.asString([
"// define __esModule on exports",
`${fn} = ${runtimeTemplate.basicFunction("exports", [
"if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {",
Template.indent([
"Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });"
]),
"}",
"Object.defineProperty(exports, '__esModule', { value: true });"
])};`
]);
}
}
module.exports = MakeNamespaceObjectRuntimeModule;

View File

@ -0,0 +1,24 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
class NonceRuntimeModule extends RuntimeModule {
constructor() {
super("nonce", RuntimeModule.STAGE_ATTACH);
}
/**
* @returns {string | null} runtime code
*/
generate() {
return `${RuntimeGlobals.scriptNonce} = undefined;`;
}
}
module.exports = NonceRuntimeModule;

View File

@ -0,0 +1,78 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Compilation")} Compilation */
class OnChunksLoadedRuntimeModule extends RuntimeModule {
constructor() {
super("chunk loaded");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return Template.asString([
"var deferred = [];",
`${RuntimeGlobals.onChunksLoaded} = ${runtimeTemplate.basicFunction(
"result, chunkIds, fn, priority",
[
"if(chunkIds) {",
Template.indent([
"priority = priority || 0;",
"for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];",
"deferred[i] = [chunkIds, fn, priority];",
"return;"
]),
"}",
"var notFulfilled = Infinity;",
"for (var i = 0; i < deferred.length; i++) {",
Template.indent([
runtimeTemplate.destructureArray(
["chunkIds", "fn", "priority"],
"deferred[i]"
),
"var fulfilled = true;",
"for (var j = 0; j < chunkIds.length; j++) {",
Template.indent([
`if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(${
RuntimeGlobals.onChunksLoaded
}).every(${runtimeTemplate.returningFunction(
`${RuntimeGlobals.onChunksLoaded}[key](chunkIds[j])`,
"key"
)})) {`,
Template.indent(["chunkIds.splice(j--, 1);"]),
"} else {",
Template.indent([
"fulfilled = false;",
"if(priority < notFulfilled) notFulfilled = priority;"
]),
"}"
]),
"}",
"if(fulfilled) {",
Template.indent([
"deferred.splice(i--, 1)",
"var r = fn();",
"if (r !== undefined) result = r;"
]),
"}"
]),
"}",
"return result;"
]
)};`
]);
}
}
module.exports = OnChunksLoadedRuntimeModule;

View File

@ -0,0 +1,37 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../Compilation")} Compilation */
class PublicPathRuntimeModule extends RuntimeModule {
/**
* @param {OutputOptions["publicPath"]} publicPath public path
*/
constructor(publicPath) {
super("publicPath", RuntimeModule.STAGE_BASIC);
this.publicPath = publicPath;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const { publicPath } = this;
const compilation = /** @type {Compilation} */ (this.compilation);
return `${RuntimeGlobals.publicPath} = ${JSON.stringify(
compilation.getPath(publicPath || "", {
hash: compilation.hash || "XXXX"
})
)};`;
}
}
module.exports = PublicPathRuntimeModule;

View File

@ -0,0 +1,44 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class RelativeUrlRuntimeModule extends HelperRuntimeModule {
constructor() {
super("relative url");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return Template.asString([
`${RuntimeGlobals.relativeUrl} = function RelativeURL(url) {`,
Template.indent([
'var realUrl = new URL(url, "x:/");',
"var values = {};",
"for (var key in realUrl) values[key] = realUrl[key];",
"values.href = url;",
'values.pathname = url.replace(/[?#].*/, "");',
'values.origin = values.protocol = "";',
`values.toString = values.toJSON = ${runtimeTemplate.returningFunction(
"url"
)};`,
"for (var key in values) Object.defineProperty(this, key, { enumerable: true, configurable: true, value: values[key] });"
]),
"};",
`${RuntimeGlobals.relativeUrl}.prototype = URL.prototype;`
]);
}
}
module.exports = RelativeUrlRuntimeModule;

View File

@ -0,0 +1,32 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
class RuntimeIdRuntimeModule extends RuntimeModule {
constructor() {
super("runtimeId");
}
/**
* @returns {string | null} runtime code
*/
generate() {
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const chunk = /** @type {Chunk} */ (this.chunk);
const runtime = chunk.runtime;
if (typeof runtime !== "string")
throw new Error("RuntimeIdRuntimeModule must be in a single runtime");
const id = chunkGraph.getRuntimeId(runtime);
return `${RuntimeGlobals.runtimeId} = ${JSON.stringify(id)};`;
}
}
module.exports = RuntimeIdRuntimeModule;

View File

@ -0,0 +1,86 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const StartupChunkDependenciesRuntimeModule = require("./StartupChunkDependenciesRuntimeModule");
const StartupEntrypointRuntimeModule = require("./StartupEntrypointRuntimeModule");
/** @typedef {import("../../declarations/WebpackOptions").ChunkLoadingType} ChunkLoadingType */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/**
* @typedef {object} Options
* @property {ChunkLoadingType} chunkLoading
* @property {boolean=} asyncChunkLoading
*/
const PLUGIN_NAME = "StartupChunkDependenciesPlugin";
class StartupChunkDependenciesPlugin {
/**
* @param {Options} options options
*/
constructor(options) {
this.chunkLoading = options.chunkLoading;
this.asyncChunkLoading =
typeof options.asyncChunkLoading === "boolean"
? options.asyncChunkLoading
: true;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, compilation => {
const globalChunkLoading = compilation.outputOptions.chunkLoading;
/**
* @param {Chunk} chunk chunk to check
* @returns {boolean} true, when the plugin is enabled for the chunk
*/
const isEnabledForChunk = chunk => {
const options = chunk.getEntryOptions();
const chunkLoading =
options && options.chunkLoading !== undefined
? options.chunkLoading
: globalChunkLoading;
return chunkLoading === this.chunkLoading;
};
compilation.hooks.additionalTreeRuntimeRequirements.tap(
PLUGIN_NAME,
(chunk, set, { chunkGraph }) => {
if (!isEnabledForChunk(chunk)) return;
if (chunkGraph.hasChunkEntryDependentChunks(chunk)) {
set.add(RuntimeGlobals.startup);
set.add(RuntimeGlobals.ensureChunk);
set.add(RuntimeGlobals.ensureChunkIncludeEntries);
compilation.addRuntimeModule(
chunk,
new StartupChunkDependenciesRuntimeModule(this.asyncChunkLoading)
);
}
}
);
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.startupEntrypoint)
.tap(PLUGIN_NAME, (chunk, set) => {
if (!isEnabledForChunk(chunk)) return;
set.add(RuntimeGlobals.require);
set.add(RuntimeGlobals.ensureChunk);
set.add(RuntimeGlobals.ensureChunkIncludeEntries);
compilation.addRuntimeModule(
chunk,
new StartupEntrypointRuntimeModule(this.asyncChunkLoading)
);
});
});
}
}
module.exports = StartupChunkDependenciesPlugin;

View File

@ -0,0 +1,75 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
class StartupChunkDependenciesRuntimeModule extends RuntimeModule {
/**
* @param {boolean} asyncChunkLoading use async chunk loading
*/
constructor(asyncChunkLoading) {
super("startup chunk dependencies", RuntimeModule.STAGE_TRIGGER);
this.asyncChunkLoading = asyncChunkLoading;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const chunk = /** @type {Chunk} */ (this.chunk);
const chunkIds = Array.from(
chunkGraph.getChunkEntryDependentChunksIterable(chunk)
).map(chunk => chunk.id);
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return Template.asString([
`var next = ${RuntimeGlobals.startup};`,
`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction(
"",
!this.asyncChunkLoading
? chunkIds
.map(
id => `${RuntimeGlobals.ensureChunk}(${JSON.stringify(id)});`
)
.concat("return next();")
: chunkIds.length === 1
? `return ${RuntimeGlobals.ensureChunk}(${JSON.stringify(
chunkIds[0]
)}).then(next);`
: chunkIds.length > 2
? [
// using map is shorter for 3 or more chunks
`return Promise.all(${JSON.stringify(chunkIds)}.map(${
RuntimeGlobals.ensureChunk
}, ${RuntimeGlobals.require})).then(next);`
]
: [
// calling ensureChunk directly is shorter for 0 - 2 chunks
"return Promise.all([",
Template.indent(
chunkIds
.map(
id =>
`${RuntimeGlobals.ensureChunk}(${JSON.stringify(id)})`
)
.join(",\n")
),
"]).then(next);"
]
)};`
]);
}
}
module.exports = StartupChunkDependenciesRuntimeModule;

View File

@ -0,0 +1,54 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../MainTemplate")} MainTemplate */
class StartupEntrypointRuntimeModule extends RuntimeModule {
/**
* @param {boolean} asyncChunkLoading use async chunk loading
*/
constructor(asyncChunkLoading) {
super("startup entrypoint");
this.asyncChunkLoading = asyncChunkLoading;
}
/**
* @returns {string | null} runtime code
*/
generate() {
const compilation = /** @type {Compilation} */ (this.compilation);
const { runtimeTemplate } = compilation;
return `${
RuntimeGlobals.startupEntrypoint
} = ${runtimeTemplate.basicFunction("result, chunkIds, fn", [
"// arguments: chunkIds, moduleId are deprecated",
"var moduleId = chunkIds;",
`if(!fn) chunkIds = result, fn = ${runtimeTemplate.returningFunction(
`${RuntimeGlobals.require}(${RuntimeGlobals.entryModuleId} = moduleId)`
)};`,
...(this.asyncChunkLoading
? [
`return Promise.all(chunkIds.map(${RuntimeGlobals.ensureChunk}, ${
RuntimeGlobals.require
})).then(${runtimeTemplate.basicFunction("", [
"var r = fn();",
"return r === undefined ? result : r;"
])})`
]
: [
`chunkIds.map(${RuntimeGlobals.ensureChunk}, ${RuntimeGlobals.require})`,
"var r = fn();",
"return r === undefined ? result : r;"
])
])}`;
}
}
module.exports = StartupEntrypointRuntimeModule;

View File

@ -0,0 +1,25 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
/** @typedef {import("../Compilation")} Compilation */
class SystemContextRuntimeModule extends RuntimeModule {
constructor() {
super("__system_context__");
}
/**
* @returns {string | null} runtime code
*/
generate() {
return `${RuntimeGlobals.systemContext} = __system_context__;`;
}
}
module.exports = SystemContextRuntimeModule;