summaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/optimize
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/optimize')
-rw-r--r--node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js100
-rw-r--r--node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js336
-rw-r--r--node_modules/webpack/lib/optimize/ConcatenatedModule.js1905
-rw-r--r--node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js88
-rw-r--r--node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js124
-rw-r--r--node_modules/webpack/lib/optimize/InnerGraph.js346
-rw-r--r--node_modules/webpack/lib/optimize/InnerGraphPlugin.js377
-rw-r--r--node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js281
-rw-r--r--node_modules/webpack/lib/optimize/MangleExportsPlugin.js177
-rw-r--r--node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js115
-rw-r--r--node_modules/webpack/lib/optimize/MinChunkSizePlugin.js113
-rw-r--r--node_modules/webpack/lib/optimize/MinMaxSizeWarning.js35
-rw-r--r--node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js942
-rw-r--r--node_modules/webpack/lib/optimize/RealContentHashPlugin.js467
-rw-r--r--node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js57
-rw-r--r--node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js127
-rw-r--r--node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js52
-rw-r--r--node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js346
-rw-r--r--node_modules/webpack/lib/optimize/SplitChunksPlugin.js1763
19 files changed, 7751 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js
new file mode 100644
index 00000000..e6f24919
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js
@@ -0,0 +1,100 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_ADVANCED } = require("../OptimizationStages");
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../Compiler")} Compiler */
+
+/**
+ * @typedef {Object} AggressiveMergingPluginOptions
+ * @property {number=} minSizeReduce minimal size reduction to trigger merging
+ */
+
+class AggressiveMergingPlugin {
+ /**
+ * @param {AggressiveMergingPluginOptions=} [options] options object
+ */
+ constructor(options) {
+ if (
+ (options !== undefined && typeof options !== "object") ||
+ Array.isArray(options)
+ ) {
+ throw new Error(
+ "Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/"
+ );
+ }
+ this.options = options || {};
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ const options = this.options;
+ const minSizeReduce = options.minSizeReduce || 1.5;
+
+ compiler.hooks.thisCompilation.tap(
+ "AggressiveMergingPlugin",
+ compilation => {
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "AggressiveMergingPlugin",
+ stage: STAGE_ADVANCED
+ },
+ chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ /** @type {{a: Chunk, b: Chunk, improvement: number}[]} */
+ let combinations = [];
+ for (const a of chunks) {
+ if (a.canBeInitial()) continue;
+ for (const b of chunks) {
+ if (b.canBeInitial()) continue;
+ if (b === a) break;
+ if (!chunkGraph.canChunksBeIntegrated(a, b)) {
+ continue;
+ }
+ const aSize = chunkGraph.getChunkSize(b, {
+ chunkOverhead: 0
+ });
+ const bSize = chunkGraph.getChunkSize(a, {
+ chunkOverhead: 0
+ });
+ const abSize = chunkGraph.getIntegratedChunksSize(b, a, {
+ chunkOverhead: 0
+ });
+ const improvement = (aSize + bSize) / abSize;
+ combinations.push({
+ a,
+ b,
+ improvement
+ });
+ }
+ }
+
+ combinations.sort((a, b) => {
+ return b.improvement - a.improvement;
+ });
+
+ const pair = combinations[0];
+
+ if (!pair) return;
+ if (pair.improvement < minSizeReduce) return;
+
+ chunkGraph.integrateChunks(pair.b, pair.a);
+ compilation.chunks.delete(pair.a);
+ return true;
+ }
+ );
+ }
+ );
+ }
+}
+
+module.exports = AggressiveMergingPlugin;
diff --git a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js
new file mode 100644
index 00000000..dde26c1b
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js
@@ -0,0 +1,336 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_ADVANCED } = require("../OptimizationStages");
+const { intersect } = require("../util/SetHelpers");
+const {
+ compareModulesByIdentifier,
+ compareChunks
+} = require("../util/comparators");
+const createSchemaValidation = require("../util/create-schema-validation");
+const identifierUtils = require("../util/identifier");
+
+/** @typedef {import("../../declarations/plugins/optimize/AggressiveSplittingPlugin").AggressiveSplittingPluginOptions} AggressiveSplittingPluginOptions */
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../ChunkGraph")} ChunkGraph */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Module")} Module */
+
+const validate = createSchemaValidation(
+ require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.check.js"),
+ () =>
+ require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"),
+ {
+ name: "Aggressive Splitting Plugin",
+ baseDataPath: "options"
+ }
+);
+
+/**
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @param {Chunk} oldChunk the old chunk
+ * @param {Chunk} newChunk the new chunk
+ * @returns {(module: Module) => void} function to move module between chunks
+ */
+const moveModuleBetween = (chunkGraph, oldChunk, newChunk) => {
+ return module => {
+ chunkGraph.disconnectChunkAndModule(oldChunk, module);
+ chunkGraph.connectChunkAndModule(newChunk, module);
+ };
+};
+
+/**
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @param {Chunk} chunk the chunk
+ * @returns {function(Module): boolean} filter for entry module
+ */
+const isNotAEntryModule = (chunkGraph, chunk) => {
+ return module => {
+ return !chunkGraph.isEntryModuleInChunk(module, chunk);
+ };
+};
+
+/** @type {WeakSet<Chunk>} */
+const recordedChunks = new WeakSet();
+
+class AggressiveSplittingPlugin {
+ /**
+ * @param {AggressiveSplittingPluginOptions=} options options object
+ */
+ constructor(options = {}) {
+ validate(options);
+
+ this.options = options;
+ if (typeof this.options.minSize !== "number") {
+ this.options.minSize = 30 * 1024;
+ }
+ if (typeof this.options.maxSize !== "number") {
+ this.options.maxSize = 50 * 1024;
+ }
+ if (typeof this.options.chunkOverhead !== "number") {
+ this.options.chunkOverhead = 0;
+ }
+ if (typeof this.options.entryChunkMultiplicator !== "number") {
+ this.options.entryChunkMultiplicator = 1;
+ }
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk to test
+ * @returns {boolean} true if the chunk was recorded
+ */
+ static wasChunkRecorded(chunk) {
+ return recordedChunks.has(chunk);
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.thisCompilation.tap(
+ "AggressiveSplittingPlugin",
+ compilation => {
+ let needAdditionalSeal = false;
+ let newSplits;
+ /** @type {Set<Chunk>} */
+ let fromAggressiveSplittingSet;
+ let chunkSplitDataMap;
+ compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => {
+ newSplits = [];
+ fromAggressiveSplittingSet = new Set();
+ chunkSplitDataMap = new Map();
+ });
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "AggressiveSplittingPlugin",
+ stage: STAGE_ADVANCED
+ },
+ chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ // Precompute stuff
+ const nameToModuleMap = new Map();
+ const moduleToNameMap = new Map();
+ const makePathsRelative =
+ identifierUtils.makePathsRelative.bindContextCache(
+ compiler.context,
+ compiler.root
+ );
+ for (const m of compilation.modules) {
+ const name = makePathsRelative(m.identifier());
+ nameToModuleMap.set(name, m);
+ moduleToNameMap.set(m, name);
+ }
+
+ // Check used chunk ids
+ const usedIds = new Set();
+ for (const chunk of chunks) {
+ usedIds.add(chunk.id);
+ }
+
+ const recordedSplits =
+ (compilation.records && compilation.records.aggressiveSplits) ||
+ [];
+ const usedSplits = newSplits
+ ? recordedSplits.concat(newSplits)
+ : recordedSplits;
+
+ const minSize = /** @type {number} */ (this.options.minSize);
+ const maxSize = /** @type {number} */ (this.options.maxSize);
+
+ const applySplit = splitData => {
+ // Cannot split if id is already taken
+ if (splitData.id !== undefined && usedIds.has(splitData.id)) {
+ return false;
+ }
+
+ // Get module objects from names
+ const selectedModules = splitData.modules.map(name =>
+ nameToModuleMap.get(name)
+ );
+
+ // Does the modules exist at all?
+ if (!selectedModules.every(Boolean)) return false;
+
+ // Check if size matches (faster than waiting for hash)
+ let size = 0;
+ for (const m of selectedModules) size += m.size();
+ if (size !== splitData.size) return false;
+
+ // get chunks with all modules
+ const selectedChunks = intersect(
+ selectedModules.map(
+ m => new Set(chunkGraph.getModuleChunksIterable(m))
+ )
+ );
+
+ // No relevant chunks found
+ if (selectedChunks.size === 0) return false;
+
+ // The found chunk is already the split or similar
+ if (
+ selectedChunks.size === 1 &&
+ chunkGraph.getNumberOfChunkModules(
+ Array.from(selectedChunks)[0]
+ ) === selectedModules.length
+ ) {
+ const chunk = Array.from(selectedChunks)[0];
+ if (fromAggressiveSplittingSet.has(chunk)) return false;
+ fromAggressiveSplittingSet.add(chunk);
+ chunkSplitDataMap.set(chunk, splitData);
+ return true;
+ }
+
+ // split the chunk into two parts
+ const newChunk = compilation.addChunk();
+ newChunk.chunkReason = "aggressive splitted";
+ for (const chunk of selectedChunks) {
+ selectedModules.forEach(
+ moveModuleBetween(chunkGraph, chunk, newChunk)
+ );
+ chunk.split(newChunk);
+ chunk.name = null;
+ }
+ fromAggressiveSplittingSet.add(newChunk);
+ chunkSplitDataMap.set(newChunk, splitData);
+
+ if (splitData.id !== null && splitData.id !== undefined) {
+ newChunk.id = splitData.id;
+ newChunk.ids = [splitData.id];
+ }
+ return true;
+ };
+
+ // try to restore to recorded splitting
+ let changed = false;
+ for (let j = 0; j < usedSplits.length; j++) {
+ const splitData = usedSplits[j];
+ if (applySplit(splitData)) changed = true;
+ }
+
+ // for any chunk which isn't splitted yet, split it and create a new entry
+ // start with the biggest chunk
+ const cmpFn = compareChunks(chunkGraph);
+ const sortedChunks = Array.from(chunks).sort((a, b) => {
+ const diff1 =
+ chunkGraph.getChunkModulesSize(b) -
+ chunkGraph.getChunkModulesSize(a);
+ if (diff1) return diff1;
+ const diff2 =
+ chunkGraph.getNumberOfChunkModules(a) -
+ chunkGraph.getNumberOfChunkModules(b);
+ if (diff2) return diff2;
+ return cmpFn(a, b);
+ });
+ for (const chunk of sortedChunks) {
+ if (fromAggressiveSplittingSet.has(chunk)) continue;
+ const size = chunkGraph.getChunkModulesSize(chunk);
+ if (
+ size > maxSize &&
+ chunkGraph.getNumberOfChunkModules(chunk) > 1
+ ) {
+ const modules = chunkGraph
+ .getOrderedChunkModules(chunk, compareModulesByIdentifier)
+ .filter(isNotAEntryModule(chunkGraph, chunk));
+ const selectedModules = [];
+ let selectedModulesSize = 0;
+ for (let k = 0; k < modules.length; k++) {
+ const module = modules[k];
+ const newSize = selectedModulesSize + module.size();
+ if (newSize > maxSize && selectedModulesSize >= minSize) {
+ break;
+ }
+ selectedModulesSize = newSize;
+ selectedModules.push(module);
+ }
+ if (selectedModules.length === 0) continue;
+ const splitData = {
+ modules: selectedModules
+ .map(m => moduleToNameMap.get(m))
+ .sort(),
+ size: selectedModulesSize
+ };
+
+ if (applySplit(splitData)) {
+ newSplits = (newSplits || []).concat(splitData);
+ changed = true;
+ }
+ }
+ }
+ if (changed) return true;
+ }
+ );
+ compilation.hooks.recordHash.tap(
+ "AggressiveSplittingPlugin",
+ records => {
+ // 4. save made splittings to records
+ const allSplits = new Set();
+ const invalidSplits = new Set();
+
+ // Check if some splittings are invalid
+ // We remove invalid splittings and try again
+ for (const chunk of compilation.chunks) {
+ const splitData = chunkSplitDataMap.get(chunk);
+ if (splitData !== undefined) {
+ if (splitData.hash && chunk.hash !== splitData.hash) {
+ // Split was successful, but hash doesn't equal
+ // We can throw away the split since it's useless now
+ invalidSplits.add(splitData);
+ }
+ }
+ }
+
+ if (invalidSplits.size > 0) {
+ records.aggressiveSplits = records.aggressiveSplits.filter(
+ splitData => !invalidSplits.has(splitData)
+ );
+ needAdditionalSeal = true;
+ } else {
+ // set hash and id values on all (new) splittings
+ for (const chunk of compilation.chunks) {
+ const splitData = chunkSplitDataMap.get(chunk);
+ if (splitData !== undefined) {
+ splitData.hash = chunk.hash;
+ splitData.id = chunk.id;
+ allSplits.add(splitData);
+ // set flag for stats
+ recordedChunks.add(chunk);
+ }
+ }
+
+ // Also add all unused historical splits (after the used ones)
+ // They can still be used in some future compilation
+ const recordedSplits =
+ compilation.records && compilation.records.aggressiveSplits;
+ if (recordedSplits) {
+ for (const splitData of recordedSplits) {
+ if (!invalidSplits.has(splitData)) allSplits.add(splitData);
+ }
+ }
+
+ // record all splits
+ records.aggressiveSplits = Array.from(allSplits);
+
+ needAdditionalSeal = false;
+ }
+ }
+ );
+ compilation.hooks.needAdditionalSeal.tap(
+ "AggressiveSplittingPlugin",
+ () => {
+ if (needAdditionalSeal) {
+ needAdditionalSeal = false;
+ return true;
+ }
+ }
+ );
+ }
+ );
+ }
+}
+module.exports = AggressiveSplittingPlugin;
diff --git a/node_modules/webpack/lib/optimize/ConcatenatedModule.js b/node_modules/webpack/lib/optimize/ConcatenatedModule.js
new file mode 100644
index 00000000..f889b5e2
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/ConcatenatedModule.js
@@ -0,0 +1,1905 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const eslintScope = require("eslint-scope");
+const Referencer = require("eslint-scope/lib/referencer");
+const {
+ CachedSource,
+ ConcatSource,
+ ReplaceSource
+} = require("webpack-sources");
+const ConcatenationScope = require("../ConcatenationScope");
+const { UsageState } = require("../ExportsInfo");
+const Module = require("../Module");
+const { JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants");
+const RuntimeGlobals = require("../RuntimeGlobals");
+const Template = require("../Template");
+const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
+const JavascriptParser = require("../javascript/JavascriptParser");
+const { equals } = require("../util/ArrayHelpers");
+const LazySet = require("../util/LazySet");
+const { concatComparators } = require("../util/comparators");
+const createHash = require("../util/createHash");
+const { makePathsRelative } = require("../util/identifier");
+const makeSerializable = require("../util/makeSerializable");
+const propertyAccess = require("../util/propertyAccess");
+const { propertyName } = require("../util/propertyName");
+const {
+ filterRuntime,
+ intersectRuntime,
+ mergeRuntimeCondition,
+ mergeRuntimeConditionNonFalse,
+ runtimeConditionToString,
+ subtractRuntimeCondition
+} = require("../util/runtime");
+
+/** @typedef {import("eslint-scope").Scope} Scope */
+/** @typedef {import("webpack-sources").Source} Source */
+/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
+/** @typedef {import("../ChunkGraph")} ChunkGraph */
+/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
+/** @typedef {import("../Compilation")} Compilation */
+/** @typedef {import("../Dependency")} Dependency */
+/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
+/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
+/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
+/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
+/** @template T @typedef {import("../InitFragment")<T>} InitFragment */
+/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
+/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
+/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
+/** @typedef {import("../ModuleGraph")} ModuleGraph */
+/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
+/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
+/** @typedef {import("../RequestShortener")} RequestShortener */
+/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
+/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
+/** @typedef {import("../WebpackError")} WebpackError */
+/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
+/** @typedef {import("../util/Hash")} Hash */
+/** @typedef {typeof import("../util/Hash")} HashConstructor */
+/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
+/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
+
+// fix eslint-scope to support class properties correctly
+// cspell:word Referencer
+const ReferencerClass = Referencer;
+if (!ReferencerClass.prototype.PropertyDefinition) {
+ ReferencerClass.prototype.PropertyDefinition =
+ ReferencerClass.prototype.Property;
+}
+
+/**
+ * @typedef {Object} ReexportInfo
+ * @property {Module} module
+ * @property {string[]} export
+ */
+
+/** @typedef {RawBinding | SymbolBinding} Binding */
+
+/**
+ * @typedef {Object} RawBinding
+ * @property {ModuleInfo} info
+ * @property {string} rawName
+ * @property {string=} comment
+ * @property {string[]} ids
+ * @property {string[]} exportName
+ */
+
+/**
+ * @typedef {Object} SymbolBinding
+ * @property {ConcatenatedModuleInfo} info
+ * @property {string} name
+ * @property {string=} comment
+ * @property {string[]} ids
+ * @property {string[]} exportName
+ */
+
+/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo } ModuleInfo */
+/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo | ReferenceToModuleInfo } ModuleInfoOrReference */
+
+/**
+ * @typedef {Object} ConcatenatedModuleInfo
+ * @property {"concatenated"} type
+ * @property {Module} module
+ * @property {number} index
+ * @property {Object} ast
+ * @property {Source} internalSource
+ * @property {ReplaceSource} source
+ * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
+ * @property {Iterable<string>} runtimeRequirements
+ * @property {Scope} globalScope
+ * @property {Scope} moduleScope
+ * @property {Map<string, string>} internalNames
+ * @property {Map<string, string>} exportMap
+ * @property {Map<string, string>} rawExportMap
+ * @property {string=} namespaceExportSymbol
+ * @property {string} namespaceObjectName
+ * @property {boolean} interopNamespaceObjectUsed
+ * @property {string} interopNamespaceObjectName
+ * @property {boolean} interopNamespaceObject2Used
+ * @property {string} interopNamespaceObject2Name
+ * @property {boolean} interopDefaultAccessUsed
+ * @property {string} interopDefaultAccessName
+ */
+
+/**
+ * @typedef {Object} ExternalModuleInfo
+ * @property {"external"} type
+ * @property {Module} module
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ * @property {number} index
+ * @property {string} name
+ * @property {boolean} interopNamespaceObjectUsed
+ * @property {string} interopNamespaceObjectName
+ * @property {boolean} interopNamespaceObject2Used
+ * @property {string} interopNamespaceObject2Name
+ * @property {boolean} interopDefaultAccessUsed
+ * @property {string} interopDefaultAccessName
+ */
+
+/**
+ * @typedef {Object} ReferenceToModuleInfo
+ * @property {"reference"} type
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ * @property {ConcatenatedModuleInfo | ExternalModuleInfo} target
+ */
+
+const RESERVED_NAMES = new Set(
+ [
+ // internal names (should always be renamed)
+ ConcatenationScope.DEFAULT_EXPORT,
+ ConcatenationScope.NAMESPACE_OBJECT_EXPORT,
+
+ // keywords
+ "abstract,arguments,async,await,boolean,break,byte,case,catch,char,class,const,continue",
+ "debugger,default,delete,do,double,else,enum,eval,export,extends,false,final,finally,float",
+ "for,function,goto,if,implements,import,in,instanceof,int,interface,let,long,native,new,null",
+ "package,private,protected,public,return,short,static,super,switch,synchronized,this,throw",
+ "throws,transient,true,try,typeof,var,void,volatile,while,with,yield",
+
+ // commonjs/amd
+ "module,__dirname,__filename,exports,require,define",
+
+ // js globals
+ "Array,Date,eval,function,hasOwnProperty,Infinity,isFinite,isNaN,isPrototypeOf,length,Math",
+ "NaN,name,Number,Object,prototype,String,toString,undefined,valueOf",
+
+ // browser globals
+ "alert,all,anchor,anchors,area,assign,blur,button,checkbox,clearInterval,clearTimeout",
+ "clientInformation,close,closed,confirm,constructor,crypto,decodeURI,decodeURIComponent",
+ "defaultStatus,document,element,elements,embed,embeds,encodeURI,encodeURIComponent,escape",
+ "event,fileUpload,focus,form,forms,frame,innerHeight,innerWidth,layer,layers,link,location",
+ "mimeTypes,navigate,navigator,frames,frameRate,hidden,history,image,images,offscreenBuffering",
+ "open,opener,option,outerHeight,outerWidth,packages,pageXOffset,pageYOffset,parent,parseFloat",
+ "parseInt,password,pkcs11,plugin,prompt,propertyIsEnum,radio,reset,screenX,screenY,scroll",
+ "secure,select,self,setInterval,setTimeout,status,submit,taint,text,textarea,top,unescape",
+ "untaint,window",
+
+ // window events
+ "onblur,onclick,onerror,onfocus,onkeydown,onkeypress,onkeyup,onmouseover,onload,onmouseup,onmousedown,onsubmit"
+ ]
+ .join(",")
+ .split(",")
+);
+
+const createComparator = (property, comparator) => (a, b) =>
+ comparator(a[property], b[property]);
+const compareNumbers = (a, b) => {
+ if (isNaN(a)) {
+ if (!isNaN(b)) {
+ return 1;
+ }
+ } else {
+ if (isNaN(b)) {
+ return -1;
+ }
+ if (a !== b) {
+ return a < b ? -1 : 1;
+ }
+ }
+ return 0;
+};
+const bySourceOrder = createComparator("sourceOrder", compareNumbers);
+const byRangeStart = createComparator("rangeStart", compareNumbers);
+
+const joinIterableWithComma = iterable => {
+ // This is more performant than Array.from().join(", ")
+ // as it doesn't create an array
+ let str = "";
+ let first = true;
+ for (const item of iterable) {
+ if (first) {
+ first = false;
+ } else {
+ str += ", ";
+ }
+ str += item;
+ }
+ return str;
+};
+
+/**
+ * @typedef {Object} ConcatenationEntry
+ * @property {"concatenated" | "external"} type
+ * @property {Module} module
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ */
+
+/**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {ModuleInfo} info module info
+ * @param {string[]} exportName exportName
+ * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
+ * @param {RuntimeSpec} runtime for which runtime
+ * @param {RequestShortener} requestShortener the request shortener
+ * @param {RuntimeTemplate} runtimeTemplate the runtime template
+ * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
+ * @param {boolean} asCall asCall
+ * @param {boolean} strictHarmonyModule strictHarmonyModule
+ * @param {boolean | undefined} asiSafe asiSafe
+ * @param {Set<ExportInfo>} alreadyVisited alreadyVisited
+ * @returns {Binding} the final variable
+ */
+const getFinalBinding = (
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ strictHarmonyModule,
+ asiSafe,
+ alreadyVisited = new Set()
+) => {
+ const exportsType = info.module.getExportsType(
+ moduleGraph,
+ strictHarmonyModule
+ );
+ if (exportName.length === 0) {
+ switch (exportsType) {
+ case "default-only":
+ info.interopNamespaceObject2Used = true;
+ return {
+ info,
+ rawName: info.interopNamespaceObject2Name,
+ ids: exportName,
+ exportName
+ };
+ case "default-with-named":
+ info.interopNamespaceObjectUsed = true;
+ return {
+ info,
+ rawName: info.interopNamespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ case "namespace":
+ case "dynamic":
+ break;
+ default:
+ throw new Error(`Unexpected exportsType ${exportsType}`);
+ }
+ } else {
+ switch (exportsType) {
+ case "namespace":
+ break;
+ case "default-with-named":
+ switch (exportName[0]) {
+ case "default":
+ exportName = exportName.slice(1);
+ break;
+ case "__esModule":
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ break;
+ case "default-only": {
+ const exportId = exportName[0];
+ if (exportId === "__esModule") {
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ exportName = exportName.slice(1);
+ if (exportId !== "default") {
+ return {
+ info,
+ rawName:
+ "/* non-default import from default-exporting module */undefined",
+ ids: exportName,
+ exportName
+ };
+ }
+ break;
+ }
+ case "dynamic":
+ switch (exportName[0]) {
+ case "default": {
+ exportName = exportName.slice(1);
+ info.interopDefaultAccessUsed = true;
+ const defaultExport = asCall
+ ? `${info.interopDefaultAccessName}()`
+ : asiSafe
+ ? `(${info.interopDefaultAccessName}())`
+ : asiSafe === false
+ ? `;(${info.interopDefaultAccessName}())`
+ : `${info.interopDefaultAccessName}.a`;
+ return {
+ info,
+ rawName: defaultExport,
+ ids: exportName,
+ exportName
+ };
+ }
+ case "__esModule":
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ break;
+ default:
+ throw new Error(`Unexpected exportsType ${exportsType}`);
+ }
+ }
+ if (exportName.length === 0) {
+ switch (info.type) {
+ case "concatenated":
+ neededNamespaceObjects.add(info);
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ case "external":
+ return { info, rawName: info.name, ids: exportName, exportName };
+ }
+ }
+ const exportsInfo = moduleGraph.getExportsInfo(info.module);
+ const exportInfo = exportsInfo.getExportInfo(exportName[0]);
+ if (alreadyVisited.has(exportInfo)) {
+ return {
+ info,
+ rawName: "/* circular reexport */ Object(function x() { x() }())",
+ ids: [],
+ exportName
+ };
+ }
+ alreadyVisited.add(exportInfo);
+ switch (info.type) {
+ case "concatenated": {
+ const exportId = exportName[0];
+ if (exportInfo.provided === false) {
+ // It's not provided, but it could be on the prototype
+ neededNamespaceObjects.add(info);
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ }
+ const directExport = info.exportMap && info.exportMap.get(exportId);
+ if (directExport) {
+ const usedName = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ if (!usedName) {
+ return {
+ info,
+ rawName: "/* unused export */ undefined",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ return {
+ info,
+ name: directExport,
+ ids: usedName.slice(1),
+ exportName
+ };
+ }
+ const rawExport = info.rawExportMap && info.rawExportMap.get(exportId);
+ if (rawExport) {
+ return {
+ info,
+ rawName: rawExport,
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ const reexport = exportInfo.findTarget(moduleGraph, module =>
+ moduleToInfoMap.has(module)
+ );
+ if (reexport === false) {
+ throw new Error(
+ `Target module of reexport from '${info.module.readableIdentifier(
+ requestShortener
+ )}' is not part of the concatenation (export '${exportId}')\nModules in the concatenation:\n${Array.from(
+ moduleToInfoMap,
+ ([m, info]) =>
+ ` * ${info.type} ${m.readableIdentifier(requestShortener)}`
+ ).join("\n")}`
+ );
+ }
+ if (reexport) {
+ const refInfo = moduleToInfoMap.get(reexport.module);
+ return getFinalBinding(
+ moduleGraph,
+ refInfo,
+ reexport.export
+ ? [...reexport.export, ...exportName.slice(1)]
+ : exportName.slice(1),
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ info.module.buildMeta.strictHarmonyModule,
+ asiSafe,
+ alreadyVisited
+ );
+ }
+ if (info.namespaceExportSymbol) {
+ const usedName = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: usedName,
+ exportName
+ };
+ }
+ throw new Error(
+ `Cannot get final name for export '${exportName.join(
+ "."
+ )}' of ${info.module.readableIdentifier(requestShortener)}`
+ );
+ }
+
+ case "external": {
+ const used = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ if (!used) {
+ return {
+ info,
+ rawName: "/* unused export */ undefined",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ const comment = equals(used, exportName)
+ ? ""
+ : Template.toNormalComment(`${exportName.join(".")}`);
+ return { info, rawName: info.name + comment, ids: used, exportName };
+ }
+ }
+};
+
+/**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {ModuleInfo} info module info
+ * @param {string[]} exportName exportName
+ * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
+ * @param {RuntimeSpec} runtime for which runtime
+ * @param {RequestShortener} requestShortener the request shortener
+ * @param {RuntimeTemplate} runtimeTemplate the runtime template
+ * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
+ * @param {boolean} asCall asCall
+ * @param {boolean} callContext callContext
+ * @param {boolean} strictHarmonyModule strictHarmonyModule
+ * @param {boolean | undefined} asiSafe asiSafe
+ * @returns {string} the final name
+ */
+const getFinalName = (
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ callContext,
+ strictHarmonyModule,
+ asiSafe
+) => {
+ const binding = getFinalBinding(
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ strictHarmonyModule,
+ asiSafe
+ );
+ {
+ const { ids, comment } = binding;
+ let reference;
+ let isPropertyAccess;
+ if ("rawName" in binding) {
+ reference = `${binding.rawName}${comment || ""}${propertyAccess(ids)}`;
+ isPropertyAccess = ids.length > 0;
+ } else {
+ const { info, name: exportId } = binding;
+ const name = info.internalNames.get(exportId);
+ if (!name) {
+ throw new Error(
+ `The export "${exportId}" in "${info.module.readableIdentifier(
+ requestShortener
+ )}" has no internal name (existing names: ${
+ Array.from(
+ info.internalNames,
+ ([name, symbol]) => `${name}: ${symbol}`
+ ).join(", ") || "none"
+ })`
+ );
+ }
+ reference = `${name}${comment || ""}${propertyAccess(ids)}`;
+ isPropertyAccess = ids.length > 1;
+ }
+ if (isPropertyAccess && asCall && callContext === false) {
+ return asiSafe
+ ? `(0,${reference})`
+ : asiSafe === false
+ ? `;(0,${reference})`
+ : `/*#__PURE__*/Object(${reference})`;
+ }
+ return reference;
+ }
+};
+
+const addScopeSymbols = (s, nameSet, scopeSet1, scopeSet2) => {
+ let scope = s;
+ while (scope) {
+ if (scopeSet1.has(scope)) break;
+ if (scopeSet2.has(scope)) break;
+ scopeSet1.add(scope);
+ for (const variable of scope.variables) {
+ nameSet.add(variable.name);
+ }
+ scope = scope.upper;
+ }
+};
+
+const getAllReferences = variable => {
+ let set = variable.references;
+ // Look for inner scope variables too (like in class Foo { t() { Foo } })
+ const identifiers = new Set(variable.identifiers);
+ for (const scope of variable.scope.childScopes) {
+ for (const innerVar of scope.variables) {
+ if (innerVar.identifiers.some(id => identifiers.has(id))) {
+ set = set.concat(innerVar.references);
+ break;
+ }
+ }
+ }
+ return set;
+};
+
+const getPathInAst = (ast, node) => {
+ if (ast === node) {
+ return [];
+ }
+
+ const nr = node.range;
+
+ const enterNode = n => {
+ if (!n) return undefined;
+ const r = n.range;
+ if (r) {
+ if (r[0] <= nr[0] && r[1] >= nr[1]) {
+ const path = getPathInAst(n, node);
+ if (path) {
+ path.push(n);
+ return path;
+ }
+ }
+ }
+ return undefined;
+ };
+
+ if (Array.isArray(ast)) {
+ for (let i = 0; i < ast.length; i++) {
+ const enterResult = enterNode(ast[i]);
+ if (enterResult !== undefined) return enterResult;
+ }
+ } else if (ast && typeof ast === "object") {
+ const keys = Object.keys(ast);
+ for (let i = 0; i < keys.length; i++) {
+ const value = ast[keys[i]];
+ if (Array.isArray(value)) {
+ const pathResult = getPathInAst(value, node);
+ if (pathResult !== undefined) return pathResult;
+ } else if (value && typeof value === "object") {
+ const enterResult = enterNode(value);
+ if (enterResult !== undefined) return enterResult;
+ }
+ }
+ }
+};
+
+const TYPES = new Set(["javascript"]);
+
+class ConcatenatedModule extends Module {
+ /**
+ * @param {Module} rootModule the root module of the concatenation
+ * @param {Set<Module>} modules all modules in the concatenation (including the root module)
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {Object=} associatedObjectForCache object for caching
+ * @param {string | HashConstructor=} hashFunction hash function to use
+ * @returns {ConcatenatedModule} the module
+ */
+ static create(
+ rootModule,
+ modules,
+ runtime,
+ associatedObjectForCache,
+ hashFunction = "md4"
+ ) {
+ const identifier = ConcatenatedModule._createIdentifier(
+ rootModule,
+ modules,
+ associatedObjectForCache,
+ hashFunction
+ );
+ return new ConcatenatedModule({
+ identifier,
+ rootModule,
+ modules,
+ runtime
+ });
+ }
+
+ /**
+ * @param {Object} options options
+ * @param {string} options.identifier the identifier of the module
+ * @param {Module=} options.rootModule the root module of the concatenation
+ * @param {RuntimeSpec} options.runtime the selected runtime
+ * @param {Set<Module>=} options.modules all concatenated modules
+ */
+ constructor({ identifier, rootModule, modules, runtime }) {
+ super(JAVASCRIPT_MODULE_TYPE_ESM, null, rootModule && rootModule.layer);
+
+ // Info from Factory
+ /** @type {string} */
+ this._identifier = identifier;
+ /** @type {Module} */
+ this.rootModule = rootModule;
+ /** @type {Set<Module>} */
+ this._modules = modules;
+ this._runtime = runtime;
+ this.factoryMeta = rootModule && rootModule.factoryMeta;
+ }
+
+ /**
+ * Assuming this module is in the cache. Update the (cached) module with
+ * the fresh module from the factory. Usually updates internal references
+ * and properties.
+ * @param {Module} module fresh module
+ * @returns {void}
+ */
+ updateCacheModule(module) {
+ throw new Error("Must not be called");
+ }
+
+ /**
+ * @returns {Set<string>} types available (do not mutate)
+ */
+ getSourceTypes() {
+ return TYPES;
+ }
+
+ get modules() {
+ return Array.from(this._modules);
+ }
+
+ /**
+ * @returns {string} a unique identifier of the module
+ */
+ identifier() {
+ return this._identifier;
+ }
+
+ /**
+ * @param {RequestShortener} requestShortener the request shortener
+ * @returns {string} a user readable identifier of the module
+ */
+ readableIdentifier(requestShortener) {
+ return (
+ this.rootModule.readableIdentifier(requestShortener) +
+ ` + ${this._modules.size - 1} modules`
+ );
+ }
+
+ /**
+ * @param {LibIdentOptions} options options
+ * @returns {string | null} an identifier for library inclusion
+ */
+ libIdent(options) {
+ return this.rootModule.libIdent(options);
+ }
+
+ /**
+ * @returns {string | null} absolute path which should be used for condition matching (usually the resource path)
+ */
+ nameForCondition() {
+ return this.rootModule.nameForCondition();
+ }
+
+ /**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
+ */
+ getSideEffectsConnectionState(moduleGraph) {
+ return this.rootModule.getSideEffectsConnectionState(moduleGraph);
+ }
+
+ /**
+ * @param {WebpackOptions} options webpack options
+ * @param {Compilation} compilation the compilation
+ * @param {ResolverWithOptions} resolver the resolver
+ * @param {InputFileSystem} fs the file system
+ * @param {function(WebpackError=): void} callback callback function
+ * @returns {void}
+ */
+ build(options, compilation, resolver, fs, callback) {
+ const { rootModule } = this;
+ this.buildInfo = {
+ strict: true,
+ cacheable: true,
+ moduleArgument: rootModule.buildInfo.moduleArgument,
+ exportsArgument: rootModule.buildInfo.exportsArgument,
+ fileDependencies: new LazySet(),
+ contextDependencies: new LazySet(),
+ missingDependencies: new LazySet(),
+ topLevelDeclarations: new Set(),
+ assets: undefined
+ };
+ this.buildMeta = rootModule.buildMeta;
+ this.clearDependenciesAndBlocks();
+ this.clearWarningsAndErrors();
+
+ for (const m of this._modules) {
+ // populate cacheable
+ if (!m.buildInfo.cacheable) {
+ this.buildInfo.cacheable = false;
+ }
+
+ // populate dependencies
+ for (const d of m.dependencies.filter(
+ dep =>
+ !(dep instanceof HarmonyImportDependency) ||
+ !this._modules.has(compilation.moduleGraph.getModule(dep))
+ )) {
+ this.dependencies.push(d);
+ }
+ // populate blocks
+ for (const d of m.blocks) {
+ this.blocks.push(d);
+ }
+
+ // populate warnings
+ const warnings = m.getWarnings();
+ if (warnings !== undefined) {
+ for (const warning of warnings) {
+ this.addWarning(warning);
+ }
+ }
+
+ // populate errors
+ const errors = m.getErrors();
+ if (errors !== undefined) {
+ for (const error of errors) {
+ this.addError(error);
+ }
+ }
+
+ // populate topLevelDeclarations
+ if (m.buildInfo.topLevelDeclarations) {
+ const topLevelDeclarations = this.buildInfo.topLevelDeclarations;
+ if (topLevelDeclarations !== undefined) {
+ for (const decl of m.buildInfo.topLevelDeclarations) {
+ topLevelDeclarations.add(decl);
+ }
+ }
+ } else {
+ this.buildInfo.topLevelDeclarations = undefined;
+ }
+
+ // populate assets
+ if (m.buildInfo.assets) {
+ if (this.buildInfo.assets === undefined) {
+ this.buildInfo.assets = Object.create(null);
+ }
+ Object.assign(this.buildInfo.assets, m.buildInfo.assets);
+ }
+ if (m.buildInfo.assetsInfo) {
+ if (this.buildInfo.assetsInfo === undefined) {
+ this.buildInfo.assetsInfo = new Map();
+ }
+ for (const [key, value] of m.buildInfo.assetsInfo) {
+ this.buildInfo.assetsInfo.set(key, value);
+ }
+ }
+ }
+ callback();
+ }
+
+ /**
+ * @param {string=} type the source type for which the size should be estimated
+ * @returns {number} the estimated size of the module (must be non-zero)
+ */
+ size(type) {
+ // Guess size from embedded modules
+ let size = 0;
+ for (const module of this._modules) {
+ size += module.size(type);
+ }
+ return size;
+ }
+
+ /**
+ * @private
+ * @param {Module} rootModule the root of the concatenation
+ * @param {Set<Module>} modulesSet a set of modules which should be concatenated
+ * @param {RuntimeSpec} runtime for this runtime
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @returns {ConcatenationEntry[]} concatenation list
+ */
+ _createConcatenationList(rootModule, modulesSet, runtime, moduleGraph) {
+ /** @type {ConcatenationEntry[]} */
+ const list = [];
+ /** @type {Map<Module, RuntimeSpec | true>} */
+ const existingEntries = new Map();
+
+ /**
+ * @param {Module} module a module
+ * @returns {Iterable<{ connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} imported modules in order
+ */
+ const getConcatenatedImports = module => {
+ let connections = Array.from(moduleGraph.getOutgoingConnections(module));
+ if (module === rootModule) {
+ for (const c of moduleGraph.getOutgoingConnections(this))
+ connections.push(c);
+ }
+ /**
+ * @type {Array<{ connection: ModuleGraphConnection, sourceOrder: number, rangeStart: number }>}
+ */
+ const references = connections
+ .filter(connection => {
+ if (!(connection.dependency instanceof HarmonyImportDependency))
+ return false;
+ return (
+ connection &&
+ connection.resolvedOriginModule === module &&
+ connection.module &&
+ connection.isTargetActive(runtime)
+ );
+ })
+ .map(connection => {
+ const dep = /** @type {HarmonyImportDependency} */ (
+ connection.dependency
+ );
+ return {
+ connection,
+ sourceOrder: dep.sourceOrder,
+ rangeStart: dep.range && dep.range[0]
+ };
+ });
+ /**
+ * bySourceOrder
+ * @example
+ * import a from "a"; // sourceOrder=1
+ * import b from "b"; // sourceOrder=2
+ *
+ * byRangeStart
+ * @example
+ * import {a, b} from "a"; // sourceOrder=1
+ * a.a(); // first range
+ * b.b(); // second range
+ *
+ * If there is no reexport, we have the same source.
+ * If there is reexport, but module has side effects, this will lead to reexport module only.
+ * If there is side-effects-free reexport, we can get simple deterministic result with range start comparison.
+ */
+ references.sort(concatComparators(bySourceOrder, byRangeStart));
+ /** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} */
+ const referencesMap = new Map();
+ for (const { connection } of references) {
+ const runtimeCondition = filterRuntime(runtime, r =>
+ connection.isTargetActive(r)
+ );
+ if (runtimeCondition === false) continue;
+ const module = connection.module;
+ const entry = referencesMap.get(module);
+ if (entry === undefined) {
+ referencesMap.set(module, { connection, runtimeCondition });
+ continue;
+ }
+ entry.runtimeCondition = mergeRuntimeConditionNonFalse(
+ entry.runtimeCondition,
+ runtimeCondition,
+ runtime
+ );
+ }
+ return referencesMap.values();
+ };
+
+ /**
+ * @param {ModuleGraphConnection} connection graph connection
+ * @param {RuntimeSpec | true} runtimeCondition runtime condition
+ * @returns {void}
+ */
+ const enterModule = (connection, runtimeCondition) => {
+ const module = connection.module;
+ if (!module) return;
+ const existingEntry = existingEntries.get(module);
+ if (existingEntry === true) {
+ return;
+ }
+ if (modulesSet.has(module)) {
+ existingEntries.set(module, true);
+ if (runtimeCondition !== true) {
+ throw new Error(
+ `Cannot runtime-conditional concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}, ${runtimeConditionToString(
+ runtimeCondition
+ )}). This should not happen.`
+ );
+ }
+ const imports = getConcatenatedImports(module);
+ for (const { connection, runtimeCondition } of imports)
+ enterModule(connection, runtimeCondition);
+ list.push({
+ type: "concatenated",
+ module: connection.module,
+ runtimeCondition
+ });
+ } else {
+ if (existingEntry !== undefined) {
+ const reducedRuntimeCondition = subtractRuntimeCondition(
+ runtimeCondition,
+ existingEntry,
+ runtime
+ );
+ if (reducedRuntimeCondition === false) return;
+ runtimeCondition = reducedRuntimeCondition;
+ existingEntries.set(
+ connection.module,
+ mergeRuntimeConditionNonFalse(
+ existingEntry,
+ runtimeCondition,
+ runtime
+ )
+ );
+ } else {
+ existingEntries.set(connection.module, runtimeCondition);
+ }
+ if (list.length > 0) {
+ const lastItem = list[list.length - 1];
+ if (
+ lastItem.type === "external" &&
+ lastItem.module === connection.module
+ ) {
+ lastItem.runtimeCondition = mergeRuntimeCondition(
+ lastItem.runtimeCondition,
+ runtimeCondition,
+ runtime
+ );
+ return;
+ }
+ }
+ list.push({
+ type: "external",
+ get module() {
+ // We need to use a getter here, because the module in the dependency
+ // could be replaced by some other process (i. e. also replaced with a
+ // concatenated module)
+ return connection.module;
+ },
+ runtimeCondition
+ });
+ }
+ };
+
+ existingEntries.set(rootModule, true);
+ const imports = getConcatenatedImports(rootModule);
+ for (const { connection, runtimeCondition } of imports)
+ enterModule(connection, runtimeCondition);
+ list.push({
+ type: "concatenated",
+ module: rootModule,
+ runtimeCondition: true
+ });
+
+ return list;
+ }
+
+ /**
+ * @param {Module} rootModule the root module of the concatenation
+ * @param {Set<Module>} modules all modules in the concatenation (including the root module)
+ * @param {Object=} associatedObjectForCache object for caching
+ * @param {string | HashConstructor=} hashFunction hash function to use
+ * @returns {string} the identifier
+ */
+ static _createIdentifier(
+ rootModule,
+ modules,
+ associatedObjectForCache,
+ hashFunction = "md4"
+ ) {
+ const cachedMakePathsRelative = makePathsRelative.bindContextCache(
+ rootModule.context,
+ associatedObjectForCache
+ );
+ let identifiers = [];
+ for (const module of modules) {
+ identifiers.push(cachedMakePathsRelative(module.identifier()));
+ }
+ identifiers.sort();
+ const hash = createHash(hashFunction);
+ hash.update(identifiers.join(" "));
+ return rootModule.identifier() + "|" + hash.digest("hex");
+ }
+
+ /**
+ * @param {LazySet<string>} fileDependencies set where file dependencies are added to
+ * @param {LazySet<string>} contextDependencies set where context dependencies are added to
+ * @param {LazySet<string>} missingDependencies set where missing dependencies are added to
+ * @param {LazySet<string>} buildDependencies set where build dependencies are added to
+ */
+ addCacheDependencies(
+ fileDependencies,
+ contextDependencies,
+ missingDependencies,
+ buildDependencies
+ ) {
+ for (const module of this._modules) {
+ module.addCacheDependencies(
+ fileDependencies,
+ contextDependencies,
+ missingDependencies,
+ buildDependencies
+ );
+ }
+ }
+
+ /**
+ * @param {CodeGenerationContext} context context for code generation
+ * @returns {CodeGenerationResult} result
+ */
+ codeGeneration({
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime: generationRuntime,
+ codeGenerationResults
+ }) {
+ /** @type {Set<string>} */
+ const runtimeRequirements = new Set();
+ const runtime = intersectRuntime(generationRuntime, this._runtime);
+
+ const requestShortener = runtimeTemplate.requestShortener;
+ // Meta info for each module
+ const [modulesWithInfo, moduleToInfoMap] = this._getModulesWithInfo(
+ moduleGraph,
+ runtime
+ );
+
+ // Set with modules that need a generated namespace object
+ /** @type {Set<ConcatenatedModuleInfo>} */
+ const neededNamespaceObjects = new Set();
+
+ // Generate source code and analyse scopes
+ // Prepare a ReplaceSource for the final source
+ for (const info of moduleToInfoMap.values()) {
+ this._analyseModule(
+ moduleToInfoMap,
+ info,
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ codeGenerationResults
+ );
+ }
+
+ // List of all used names to avoid conflicts
+ const allUsedNames = new Set(RESERVED_NAMES);
+ // Updated Top level declarations are created by renaming
+ const topLevelDeclarations = new Set();
+
+ // List of additional names in scope for module references
+ /** @type {Map<string, { usedNames: Set<string>, alreadyCheckedScopes: Set<TODO> }>} */
+ const usedNamesInScopeInfo = new Map();
+ /**
+ * @param {string} module module identifier
+ * @param {string} id export id
+ * @returns {{ usedNames: Set<string>, alreadyCheckedScopes: Set<TODO> }} info
+ */
+ const getUsedNamesInScopeInfo = (module, id) => {
+ const key = `${module}-${id}`;
+ let info = usedNamesInScopeInfo.get(key);
+ if (info === undefined) {
+ info = {
+ usedNames: new Set(),
+ alreadyCheckedScopes: new Set()
+ };
+ usedNamesInScopeInfo.set(key, info);
+ }
+ return info;
+ };
+
+ // Set of already checked scopes
+ const ignoredScopes = new Set();
+
+ // get all global names
+ for (const info of modulesWithInfo) {
+ if (info.type === "concatenated") {
+ // ignore symbols from moduleScope
+ if (info.moduleScope) {
+ ignoredScopes.add(info.moduleScope);
+ }
+
+ // The super class expression in class scopes behaves weird
+ // We get ranges of all super class expressions to make
+ // renaming to work correctly
+ const superClassCache = new WeakMap();
+ const getSuperClassExpressions = scope => {
+ const cacheEntry = superClassCache.get(scope);
+ if (cacheEntry !== undefined) return cacheEntry;
+ const superClassExpressions = [];
+ for (const childScope of scope.childScopes) {
+ if (childScope.type !== "class") continue;
+ const block = childScope.block;
+ if (
+ (block.type === "ClassDeclaration" ||
+ block.type === "ClassExpression") &&
+ block.superClass
+ ) {
+ superClassExpressions.push({
+ range: block.superClass.range,
+ variables: childScope.variables
+ });
+ }
+ }
+ superClassCache.set(scope, superClassExpressions);
+ return superClassExpressions;
+ };
+
+ // add global symbols
+ if (info.globalScope) {
+ for (const reference of info.globalScope.through) {
+ const name = reference.identifier.name;
+ if (ConcatenationScope.isModuleReference(name)) {
+ const match = ConcatenationScope.matchModuleReference(name);
+ if (!match) continue;
+ const referencedInfo = modulesWithInfo[match.index];
+ if (referencedInfo.type === "reference")
+ throw new Error("Module reference can't point to a reference");
+ const binding = getFinalBinding(
+ moduleGraph,
+ referencedInfo,
+ match.ids,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ info.module.buildMeta.strictHarmonyModule,
+ true
+ );
+ if (!binding.ids) continue;
+ const { usedNames, alreadyCheckedScopes } =
+ getUsedNamesInScopeInfo(
+ binding.info.module.identifier(),
+ "name" in binding ? binding.name : ""
+ );
+ for (const expr of getSuperClassExpressions(reference.from)) {
+ if (
+ expr.range[0] <= reference.identifier.range[0] &&
+ expr.range[1] >= reference.identifier.range[1]
+ ) {
+ for (const variable of expr.variables) {
+ usedNames.add(variable.name);
+ }
+ }
+ }
+ addScopeSymbols(
+ reference.from,
+ usedNames,
+ alreadyCheckedScopes,
+ ignoredScopes
+ );
+ } else {
+ allUsedNames.add(name);
+ }
+ }
+ }
+ }
+ }
+
+ // generate names for symbols
+ for (const info of moduleToInfoMap.values()) {
+ const { usedNames: namespaceObjectUsedNames } = getUsedNamesInScopeInfo(
+ info.module.identifier(),
+ ""
+ );
+ switch (info.type) {
+ case "concatenated": {
+ for (const variable of info.moduleScope.variables) {
+ const name = variable.name;
+ const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
+ info.module.identifier(),
+ name
+ );
+ if (allUsedNames.has(name) || usedNames.has(name)) {
+ const references = getAllReferences(variable);
+ for (const ref of references) {
+ addScopeSymbols(
+ ref.from,
+ usedNames,
+ alreadyCheckedScopes,
+ ignoredScopes
+ );
+ }
+ const newName = this.findNewName(
+ name,
+ allUsedNames,
+ usedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(newName);
+ info.internalNames.set(name, newName);
+ topLevelDeclarations.add(newName);
+ const source = info.source;
+ const allIdentifiers = new Set(
+ references.map(r => r.identifier).concat(variable.identifiers)
+ );
+ for (const identifier of allIdentifiers) {
+ const r = identifier.range;
+ const path = getPathInAst(info.ast, identifier);
+ if (path && path.length > 1) {
+ const maybeProperty =
+ path[1].type === "AssignmentPattern" &&
+ path[1].left === path[0]
+ ? path[2]
+ : path[1];
+ if (
+ maybeProperty.type === "Property" &&
+ maybeProperty.shorthand
+ ) {
+ source.insert(r[1], `: ${newName}`);
+ continue;
+ }
+ }
+ source.replace(r[0], r[1] - 1, newName);
+ }
+ } else {
+ allUsedNames.add(name);
+ info.internalNames.set(name, name);
+ topLevelDeclarations.add(name);
+ }
+ }
+ let namespaceObjectName;
+ if (info.namespaceExportSymbol) {
+ namespaceObjectName = info.internalNames.get(
+ info.namespaceExportSymbol
+ );
+ } else {
+ namespaceObjectName = this.findNewName(
+ "namespaceObject",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(namespaceObjectName);
+ }
+ info.namespaceObjectName = namespaceObjectName;
+ topLevelDeclarations.add(namespaceObjectName);
+ break;
+ }
+ case "external": {
+ const externalName = this.findNewName(
+ "",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalName);
+ info.name = externalName;
+ topLevelDeclarations.add(externalName);
+ break;
+ }
+ }
+ if (info.module.buildMeta.exportsType !== "namespace") {
+ const externalNameInterop = this.findNewName(
+ "namespaceObject",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopNamespaceObjectName = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ if (
+ info.module.buildMeta.exportsType === "default" &&
+ info.module.buildMeta.defaultObject !== "redirect"
+ ) {
+ const externalNameInterop = this.findNewName(
+ "namespaceObject2",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopNamespaceObject2Name = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ if (
+ info.module.buildMeta.exportsType === "dynamic" ||
+ !info.module.buildMeta.exportsType
+ ) {
+ const externalNameInterop = this.findNewName(
+ "default",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopDefaultAccessName = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ }
+
+ // Find and replace references to modules
+ for (const info of moduleToInfoMap.values()) {
+ if (info.type === "concatenated") {
+ for (const reference of info.globalScope.through) {
+ const name = reference.identifier.name;
+ const match = ConcatenationScope.matchModuleReference(name);
+ if (match) {
+ const referencedInfo = modulesWithInfo[match.index];
+ if (referencedInfo.type === "reference")
+ throw new Error("Module reference can't point to a reference");
+ const finalName = getFinalName(
+ moduleGraph,
+ referencedInfo,
+ match.ids,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ match.call,
+ !match.directImport,
+ info.module.buildMeta.strictHarmonyModule,
+ match.asiSafe
+ );
+ const r = reference.identifier.range;
+ const source = info.source;
+ // range is extended by 2 chars to cover the appended "._"
+ source.replace(r[0], r[1] + 1, finalName);
+ }
+ }
+ }
+ }
+
+ // Map with all root exposed used exports
+ /** @type {Map<string, function(RequestShortener): string>} */
+ const exportsMap = new Map();
+
+ // Set with all root exposed unused exports
+ /** @type {Set<string>} */
+ const unusedExports = new Set();
+
+ const rootInfo = /** @type {ConcatenatedModuleInfo} */ (
+ moduleToInfoMap.get(this.rootModule)
+ );
+ const strictHarmonyModule = rootInfo.module.buildMeta.strictHarmonyModule;
+ const exportsInfo = moduleGraph.getExportsInfo(rootInfo.module);
+ for (const exportInfo of exportsInfo.orderedExports) {
+ const name = exportInfo.name;
+ if (exportInfo.provided === false) continue;
+ const used = exportInfo.getUsedName(undefined, runtime);
+ if (!used) {
+ unusedExports.add(name);
+ continue;
+ }
+ exportsMap.set(used, requestShortener => {
+ try {
+ const finalName = getFinalName(
+ moduleGraph,
+ rootInfo,
+ [name],
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ false,
+ strictHarmonyModule,
+ true
+ );
+ return `/* ${
+ exportInfo.isReexport() ? "reexport" : "binding"
+ } */ ${finalName}`;
+ } catch (e) {
+ e.message += `\nwhile generating the root export '${name}' (used name: '${used}')`;
+ throw e;
+ }
+ });
+ }
+
+ const result = new ConcatSource();
+
+ // add harmony compatibility flag (must be first because of possible circular dependencies)
+ if (
+ moduleGraph.getExportsInfo(this).otherExportsInfo.getUsed(runtime) !==
+ UsageState.Unused
+ ) {
+ result.add(`// ESM COMPAT FLAG\n`);
+ result.add(
+ runtimeTemplate.defineEsModuleFlagStatement({
+ exportsArgument: this.exportsArgument,
+ runtimeRequirements
+ })
+ );
+ }
+
+ // define exports
+ if (exportsMap.size > 0) {
+ runtimeRequirements.add(RuntimeGlobals.exports);
+ runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
+ const definitions = [];
+ for (const [key, value] of exportsMap) {
+ definitions.push(
+ `\n ${propertyName(key)}: ${runtimeTemplate.returningFunction(
+ value(requestShortener)
+ )}`
+ );
+ }
+ result.add(`\n// EXPORTS\n`);
+ result.add(
+ `${RuntimeGlobals.definePropertyGetters}(${
+ this.exportsArgument
+ }, {${definitions.join(",")}\n});\n`
+ );
+ }
+
+ // list unused exports
+ if (unusedExports.size > 0) {
+ result.add(
+ `\n// UNUSED EXPORTS: ${joinIterableWithComma(unusedExports)}\n`
+ );
+ }
+
+ // generate namespace objects
+ const namespaceObjectSources = new Map();
+ for (const info of neededNamespaceObjects) {
+ if (info.namespaceExportSymbol) continue;
+ const nsObj = [];
+ const exportsInfo = moduleGraph.getExportsInfo(info.module);
+ for (const exportInfo of exportsInfo.orderedExports) {
+ if (exportInfo.provided === false) continue;
+ const usedName = exportInfo.getUsedName(undefined, runtime);
+ if (usedName) {
+ const finalName = getFinalName(
+ moduleGraph,
+ info,
+ [exportInfo.name],
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ undefined,
+ info.module.buildMeta.strictHarmonyModule,
+ true
+ );
+ nsObj.push(
+ `\n ${propertyName(usedName)}: ${runtimeTemplate.returningFunction(
+ finalName
+ )}`
+ );
+ }
+ }
+ const name = info.namespaceObjectName;
+ const defineGetters =
+ nsObj.length > 0
+ ? `${RuntimeGlobals.definePropertyGetters}(${name}, {${nsObj.join(
+ ","
+ )}\n});\n`
+ : "";
+ if (nsObj.length > 0)
+ runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
+ namespaceObjectSources.set(
+ info,
+ `
+// NAMESPACE OBJECT: ${info.module.readableIdentifier(requestShortener)}
+var ${name} = {};
+${RuntimeGlobals.makeNamespaceObject}(${name});
+${defineGetters}`
+ );
+ runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
+ }
+
+ // define required namespace objects (must be before evaluation modules)
+ for (const info of modulesWithInfo) {
+ if (info.type === "concatenated") {
+ const source = namespaceObjectSources.get(info);
+ if (!source) continue;
+ result.add(source);
+ }
+ }
+
+ const chunkInitFragments = [];
+
+ // evaluate modules in order
+ for (const rawInfo of modulesWithInfo) {
+ let name;
+ let isConditional = false;
+ const info = rawInfo.type === "reference" ? rawInfo.target : rawInfo;
+ switch (info.type) {
+ case "concatenated": {
+ result.add(
+ `\n;// CONCATENATED MODULE: ${info.module.readableIdentifier(
+ requestShortener
+ )}\n`
+ );
+ result.add(info.source);
+ if (info.chunkInitFragments) {
+ for (const f of info.chunkInitFragments) chunkInitFragments.push(f);
+ }
+ if (info.runtimeRequirements) {
+ for (const r of info.runtimeRequirements) {
+ runtimeRequirements.add(r);
+ }
+ }
+ name = info.namespaceObjectName;
+ break;
+ }
+ case "external": {
+ result.add(
+ `\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
+ requestShortener
+ )}\n`
+ );
+ runtimeRequirements.add(RuntimeGlobals.require);
+ const { runtimeCondition } =
+ /** @type {ExternalModuleInfo | ReferenceToModuleInfo} */ (rawInfo);
+ const condition = runtimeTemplate.runtimeConditionExpression({
+ chunkGraph,
+ runtimeCondition,
+ runtime,
+ runtimeRequirements
+ });
+ if (condition !== "true") {
+ isConditional = true;
+ result.add(`if (${condition}) {\n`);
+ }
+ result.add(
+ `var ${info.name} = ${RuntimeGlobals.require}(${JSON.stringify(
+ chunkGraph.getModuleId(info.module)
+ )});`
+ );
+ name = info.name;
+ break;
+ }
+ default:
+ // @ts-expect-error never is expected here
+ throw new Error(`Unsupported concatenation entry type ${info.type}`);
+ }
+ if (info.interopNamespaceObjectUsed) {
+ runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
+ result.add(
+ `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);`
+ );
+ }
+ if (info.interopNamespaceObject2Used) {
+ runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
+ result.add(
+ `\nvar ${info.interopNamespaceObject2Name} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});`
+ );
+ }
+ if (info.interopDefaultAccessUsed) {
+ runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
+ result.add(
+ `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});`
+ );
+ }
+ if (isConditional) {
+ result.add("\n}");
+ }
+ }
+
+ const data = new Map();
+ if (chunkInitFragments.length > 0)
+ data.set("chunkInitFragments", chunkInitFragments);
+ data.set("topLevelDeclarations", topLevelDeclarations);
+
+ /** @type {CodeGenerationResult} */
+ const resultEntry = {
+ sources: new Map([["javascript", new CachedSource(result)]]),
+ data,
+ runtimeRequirements
+ };
+
+ return resultEntry;
+ }
+
+ /**
+ * @param {Map<Module, ModuleInfo>} modulesMap modulesMap
+ * @param {ModuleInfo} info info
+ * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
+ * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
+ * @param {ModuleGraph} moduleGraph moduleGraph
+ * @param {ChunkGraph} chunkGraph chunkGraph
+ * @param {RuntimeSpec} runtime runtime
+ * @param {CodeGenerationResults} codeGenerationResults codeGenerationResults
+ */
+ _analyseModule(
+ modulesMap,
+ info,
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ codeGenerationResults
+ ) {
+ if (info.type === "concatenated") {
+ const m = info.module;
+ try {
+ // Create a concatenation scope to track and capture information
+ const concatenationScope = new ConcatenationScope(modulesMap, info);
+
+ // TODO cache codeGeneration results
+ const codeGenResult = m.codeGeneration({
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ concatenationScope,
+ codeGenerationResults,
+ sourceTypes: TYPES
+ });
+ const source = codeGenResult.sources.get("javascript");
+ const data = codeGenResult.data;
+ const chunkInitFragments = data && data.get("chunkInitFragments");
+ const code = source.source().toString();
+ let ast;
+ try {
+ ast = JavascriptParser._parse(code, {
+ sourceType: "module"
+ });
+ } catch (err) {
+ if (
+ err.loc &&
+ typeof err.loc === "object" &&
+ typeof err.loc.line === "number"
+ ) {
+ const lineNumber = err.loc.line;
+ const lines = code.split("\n");
+ err.message +=
+ "\n| " +
+ lines
+ .slice(Math.max(0, lineNumber - 3), lineNumber + 2)
+ .join("\n| ");
+ }
+ throw err;
+ }
+ const scopeManager = eslintScope.analyze(ast, {
+ ecmaVersion: 6,
+ sourceType: "module",
+ optimistic: true,
+ ignoreEval: true,
+ impliedStrict: true
+ });
+ const globalScope = scopeManager.acquire(ast);
+ const moduleScope = globalScope.childScopes[0];
+ const resultSource = new ReplaceSource(source);
+ info.runtimeRequirements = codeGenResult.runtimeRequirements;
+ info.ast = ast;
+ info.internalSource = source;
+ info.source = resultSource;
+ info.chunkInitFragments = chunkInitFragments;
+ info.globalScope = globalScope;
+ info.moduleScope = moduleScope;
+ } catch (err) {
+ err.message += `\nwhile analyzing module ${m.identifier()} for concatenation`;
+ throw err;
+ }
+ }
+ }
+
+ /**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {[ModuleInfoOrReference[], Map<Module, ModuleInfo>]} module info items
+ */
+ _getModulesWithInfo(moduleGraph, runtime) {
+ const orderedConcatenationList = this._createConcatenationList(
+ this.rootModule,
+ this._modules,
+ runtime,
+ moduleGraph
+ );
+ /** @type {Map<Module, ModuleInfo>} */
+ const map = new Map();
+ const list = orderedConcatenationList.map((info, index) => {
+ let item = map.get(info.module);
+ if (item === undefined) {
+ switch (info.type) {
+ case "concatenated":
+ item = {
+ type: "concatenated",
+ module: info.module,
+ index,
+ ast: undefined,
+ internalSource: undefined,
+ runtimeRequirements: undefined,
+ source: undefined,
+ globalScope: undefined,
+ moduleScope: undefined,
+ internalNames: new Map(),
+ exportMap: undefined,
+ rawExportMap: undefined,
+ namespaceExportSymbol: undefined,
+ namespaceObjectName: undefined,
+ interopNamespaceObjectUsed: false,
+ interopNamespaceObjectName: undefined,
+ interopNamespaceObject2Used: false,
+ interopNamespaceObject2Name: undefined,
+ interopDefaultAccessUsed: false,
+ interopDefaultAccessName: undefined
+ };
+ break;
+ case "external":
+ item = {
+ type: "external",
+ module: info.module,
+ runtimeCondition: info.runtimeCondition,
+ index,
+ name: undefined,
+ interopNamespaceObjectUsed: false,
+ interopNamespaceObjectName: undefined,
+ interopNamespaceObject2Used: false,
+ interopNamespaceObject2Name: undefined,
+ interopDefaultAccessUsed: false,
+ interopDefaultAccessName: undefined
+ };
+ break;
+ default:
+ throw new Error(
+ `Unsupported concatenation entry type ${info.type}`
+ );
+ }
+ map.set(item.module, item);
+ return item;
+ } else {
+ /** @type {ReferenceToModuleInfo} */
+ const ref = {
+ type: "reference",
+ runtimeCondition: info.runtimeCondition,
+ target: item
+ };
+ return ref;
+ }
+ });
+ return [list, map];
+ }
+
+ findNewName(oldName, usedNamed1, usedNamed2, extraInfo) {
+ let name = oldName;
+
+ if (name === ConcatenationScope.DEFAULT_EXPORT) {
+ name = "";
+ }
+ if (name === ConcatenationScope.NAMESPACE_OBJECT_EXPORT) {
+ name = "namespaceObject";
+ }
+
+ // Remove uncool stuff
+ extraInfo = extraInfo.replace(
+ /\.+\/|(\/index)?\.([a-zA-Z0-9]{1,4})($|\s|\?)|\s*\+\s*\d+\s*modules/g,
+ ""
+ );
+
+ const splittedInfo = extraInfo.split("/");
+ while (splittedInfo.length) {
+ name = splittedInfo.pop() + (name ? "_" + name : "");
+ const nameIdent = Template.toIdentifier(name);
+ if (
+ !usedNamed1.has(nameIdent) &&
+ (!usedNamed2 || !usedNamed2.has(nameIdent))
+ )
+ return nameIdent;
+ }
+
+ let i = 0;
+ let nameWithNumber = Template.toIdentifier(`${name}_${i}`);
+ while (
+ usedNamed1.has(nameWithNumber) ||
+ (usedNamed2 && usedNamed2.has(nameWithNumber))
+ ) {
+ i++;
+ nameWithNumber = Template.toIdentifier(`${name}_${i}`);
+ }
+ return nameWithNumber;
+ }
+
+ /**
+ * @param {Hash} hash the hash used to track dependencies
+ * @param {UpdateHashContext} context context
+ * @returns {void}
+ */
+ updateHash(hash, context) {
+ const { chunkGraph, runtime } = context;
+ for (const info of this._createConcatenationList(
+ this.rootModule,
+ this._modules,
+ intersectRuntime(runtime, this._runtime),
+ chunkGraph.moduleGraph
+ )) {
+ switch (info.type) {
+ case "concatenated":
+ info.module.updateHash(hash, context);
+ break;
+ case "external":
+ hash.update(`${chunkGraph.getModuleId(info.module)}`);
+ // TODO runtimeCondition
+ break;
+ }
+ }
+ super.updateHash(hash, context);
+ }
+
+ static deserialize(context) {
+ const obj = new ConcatenatedModule({
+ identifier: undefined,
+ rootModule: undefined,
+ modules: undefined,
+ runtime: undefined
+ });
+ obj.deserialize(context);
+ return obj;
+ }
+}
+
+makeSerializable(ConcatenatedModule, "webpack/lib/optimize/ConcatenatedModule");
+
+module.exports = ConcatenatedModule;
diff --git a/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js
new file mode 100644
index 00000000..8a32cc25
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js
@@ -0,0 +1,88 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_BASIC } = require("../OptimizationStages");
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../ChunkGroup")} ChunkGroup */
+/** @typedef {import("../Compiler")} Compiler */
+
+class EnsureChunkConditionsPlugin {
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap(
+ "EnsureChunkConditionsPlugin",
+ compilation => {
+ /**
+ * @param {Iterable<Chunk>} chunks the chunks
+ */
+ const handler = chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ // These sets are hoisted here to save memory
+ // They are cleared at the end of every loop
+ /** @type {Set<Chunk>} */
+ const sourceChunks = new Set();
+ /** @type {Set<ChunkGroup>} */
+ const chunkGroups = new Set();
+ for (const module of compilation.modules) {
+ if (!module.hasChunkCondition()) continue;
+ for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
+ if (!module.chunkCondition(chunk, compilation)) {
+ sourceChunks.add(chunk);
+ for (const group of chunk.groupsIterable) {
+ chunkGroups.add(group);
+ }
+ }
+ }
+ if (sourceChunks.size === 0) continue;
+ /** @type {Set<Chunk>} */
+ const targetChunks = new Set();
+ chunkGroupLoop: for (const chunkGroup of chunkGroups) {
+ // Can module be placed in a chunk of this group?
+ for (const chunk of chunkGroup.chunks) {
+ if (module.chunkCondition(chunk, compilation)) {
+ targetChunks.add(chunk);
+ continue chunkGroupLoop;
+ }
+ }
+ // We reached the entrypoint: fail
+ if (chunkGroup.isInitial()) {
+ throw new Error(
+ "Cannot fullfil chunk condition of " + module.identifier()
+ );
+ }
+ // Try placing in all parents
+ for (const group of chunkGroup.parentsIterable) {
+ chunkGroups.add(group);
+ }
+ }
+ for (const sourceChunk of sourceChunks) {
+ chunkGraph.disconnectChunkAndModule(sourceChunk, module);
+ }
+ for (const targetChunk of targetChunks) {
+ chunkGraph.connectChunkAndModule(targetChunk, module);
+ }
+ sourceChunks.clear();
+ chunkGroups.clear();
+ }
+ };
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "EnsureChunkConditionsPlugin",
+ stage: STAGE_BASIC
+ },
+ handler
+ );
+ }
+ );
+ }
+}
+module.exports = EnsureChunkConditionsPlugin;
diff --git a/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js
new file mode 100644
index 00000000..38367f20
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js
@@ -0,0 +1,124 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../Chunk").ChunkId} ChunkId */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Module")} Module */
+
+class FlagIncludedChunksPlugin {
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => {
+ compilation.hooks.optimizeChunkIds.tap(
+ "FlagIncludedChunksPlugin",
+ chunks => {
+ const chunkGraph = compilation.chunkGraph;
+
+ // prepare two bit integers for each module
+ // 2^31 is the max number represented as SMI in v8
+ // we want the bits distributed this way:
+ // the bit 2^31 is pretty rar and only one module should get it
+ // so it has a probability of 1 / modulesCount
+ // the first bit (2^0) is the easiest and every module could get it
+ // if it doesn't get a better bit
+ // from bit 2^n to 2^(n+1) there is a probability of p
+ // so 1 / modulesCount == p^31
+ // <=> p = sqrt31(1 / modulesCount)
+ // so we use a modulo of 1 / sqrt31(1 / modulesCount)
+ /** @type {WeakMap<Module, number>} */
+ const moduleBits = new WeakMap();
+ const modulesCount = compilation.modules.size;
+
+ // precalculate the modulo values for each bit
+ const modulo = 1 / Math.pow(1 / modulesCount, 1 / 31);
+ const modulos = Array.from(
+ { length: 31 },
+ (x, i) => Math.pow(modulo, i) | 0
+ );
+
+ // iterate all modules to generate bit values
+ let i = 0;
+ for (const module of compilation.modules) {
+ let bit = 30;
+ while (i % modulos[bit] !== 0) {
+ bit--;
+ }
+ moduleBits.set(module, 1 << bit);
+ i++;
+ }
+
+ // iterate all chunks to generate bitmaps
+ /** @type {WeakMap<Chunk, number>} */
+ const chunkModulesHash = new WeakMap();
+ for (const chunk of chunks) {
+ let hash = 0;
+ for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
+ hash |= /** @type {number} */ (moduleBits.get(module));
+ }
+ chunkModulesHash.set(chunk, hash);
+ }
+
+ for (const chunkA of chunks) {
+ const chunkAHash =
+ /** @type {number} */
+ (chunkModulesHash.get(chunkA));
+ const chunkAModulesCount =
+ chunkGraph.getNumberOfChunkModules(chunkA);
+ if (chunkAModulesCount === 0) continue;
+ let bestModule = undefined;
+ for (const module of chunkGraph.getChunkModulesIterable(chunkA)) {
+ if (
+ bestModule === undefined ||
+ chunkGraph.getNumberOfModuleChunks(bestModule) >
+ chunkGraph.getNumberOfModuleChunks(module)
+ )
+ bestModule = module;
+ }
+ loopB: for (const chunkB of chunkGraph.getModuleChunksIterable(
+ /** @type {Module} */ (bestModule)
+ )) {
+ // as we iterate the same iterables twice
+ // skip if we find ourselves
+ if (chunkA === chunkB) continue;
+
+ const chunkBModulesCount =
+ chunkGraph.getNumberOfChunkModules(chunkB);
+
+ // ids for empty chunks are not included
+ if (chunkBModulesCount === 0) continue;
+
+ // instead of swapping A and B just bail
+ // as we loop twice the current A will be B and B then A
+ if (chunkAModulesCount > chunkBModulesCount) continue;
+
+ // is chunkA in chunkB?
+
+ // we do a cheap check for the hash value
+ const chunkBHash =
+ /** @type {number} */
+ (chunkModulesHash.get(chunkB));
+ if ((chunkBHash & chunkAHash) !== chunkAHash) continue;
+
+ // compare all modules
+ for (const m of chunkGraph.getChunkModulesIterable(chunkA)) {
+ if (!chunkGraph.isModuleInChunk(m, chunkB)) continue loopB;
+ }
+ /** @type {ChunkId[]} */
+ (chunkB.ids).push(/** @type {ChunkId} */ (chunkA.id));
+ }
+ }
+ }
+ );
+ });
+ }
+}
+module.exports = FlagIncludedChunksPlugin;
diff --git a/node_modules/webpack/lib/optimize/InnerGraph.js b/node_modules/webpack/lib/optimize/InnerGraph.js
new file mode 100644
index 00000000..68ce4f36
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/InnerGraph.js
@@ -0,0 +1,346 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Sergey Melyukov @smelukov
+*/
+
+"use strict";
+
+const { UsageState } = require("../ExportsInfo");
+
+/** @typedef {import("estree").Node} AnyNode */
+/** @typedef {import("../Dependency")} Dependency */
+/** @typedef {import("../ModuleGraph")} ModuleGraph */
+/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
+/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
+/** @typedef {import("../Parser").ParserState} ParserState */
+/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
+/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
+
+/** @typedef {Map<TopLevelSymbol | null, Set<string | TopLevelSymbol> | true | undefined>} InnerGraph */
+/** @typedef {function(boolean | Set<string> | undefined): void} UsageCallback */
+
+/**
+ * @typedef {Object} StateObject
+ * @property {InnerGraph} innerGraph
+ * @property {TopLevelSymbol=} currentTopLevelSymbol
+ * @property {Map<TopLevelSymbol, Set<UsageCallback>>} usageCallbackMap
+ */
+
+/** @typedef {false|StateObject} State */
+
+/** @type {WeakMap<ParserState, State>} */
+const parserStateMap = new WeakMap();
+const topLevelSymbolTag = Symbol("top level symbol");
+
+/**
+ * @param {ParserState} parserState parser state
+ * @returns {State | undefined} state
+ */
+function getState(parserState) {
+ return parserStateMap.get(parserState);
+}
+
+/**
+ * @param {ParserState} parserState parser state
+ * @returns {void}
+ */
+exports.bailout = parserState => {
+ parserStateMap.set(parserState, false);
+};
+
+/**
+ * @param {ParserState} parserState parser state
+ * @returns {void}
+ */
+exports.enable = parserState => {
+ const state = parserStateMap.get(parserState);
+ if (state === false) {
+ return;
+ }
+ parserStateMap.set(parserState, {
+ innerGraph: new Map(),
+ currentTopLevelSymbol: undefined,
+ usageCallbackMap: new Map()
+ });
+};
+
+/**
+ * @param {ParserState} parserState parser state
+ * @returns {boolean} true, when enabled
+ */
+exports.isEnabled = parserState => {
+ const state = parserStateMap.get(parserState);
+ return !!state;
+};
+
+/**
+ * @param {ParserState} state parser state
+ * @param {TopLevelSymbol | null} symbol the symbol, or null for all symbols
+ * @param {string | TopLevelSymbol | true} usage usage data
+ * @returns {void}
+ */
+exports.addUsage = (state, symbol, usage) => {
+ const innerGraphState = getState(state);
+
+ if (innerGraphState) {
+ const { innerGraph } = innerGraphState;
+ const info = innerGraph.get(symbol);
+ if (usage === true) {
+ innerGraph.set(symbol, true);
+ } else if (info === undefined) {
+ innerGraph.set(symbol, new Set([usage]));
+ } else if (info !== true) {
+ info.add(usage);
+ }
+ }
+};
+
+/**
+ * @param {JavascriptParser} parser the parser
+ * @param {string} name name of variable
+ * @param {string | TopLevelSymbol | true} usage usage data
+ * @returns {void}
+ */
+exports.addVariableUsage = (parser, name, usage) => {
+ const symbol =
+ /** @type {TopLevelSymbol} */ (
+ parser.getTagData(name, topLevelSymbolTag)
+ ) || exports.tagTopLevelSymbol(parser, name);
+ if (symbol) {
+ exports.addUsage(parser.state, symbol, usage);
+ }
+};
+
+/**
+ * @param {ParserState} state parser state
+ * @returns {void}
+ */
+exports.inferDependencyUsage = state => {
+ const innerGraphState = getState(state);
+
+ if (!innerGraphState) {
+ return;
+ }
+
+ const { innerGraph, usageCallbackMap } = innerGraphState;
+ const processed = new Map();
+ // flatten graph to terminal nodes (string, undefined or true)
+ const nonTerminal = new Set(innerGraph.keys());
+ while (nonTerminal.size > 0) {
+ for (const key of nonTerminal) {
+ /** @type {Set<string|TopLevelSymbol> | true} */
+ let newSet = new Set();
+ let isTerminal = true;
+ const value = innerGraph.get(key);
+ let alreadyProcessed = processed.get(key);
+ if (alreadyProcessed === undefined) {
+ alreadyProcessed = new Set();
+ processed.set(key, alreadyProcessed);
+ }
+ if (value !== true && value !== undefined) {
+ for (const item of value) {
+ alreadyProcessed.add(item);
+ }
+ for (const item of value) {
+ if (typeof item === "string") {
+ newSet.add(item);
+ } else {
+ const itemValue = innerGraph.get(item);
+ if (itemValue === true) {
+ newSet = true;
+ break;
+ }
+ if (itemValue !== undefined) {
+ for (const i of itemValue) {
+ if (i === key) continue;
+ if (alreadyProcessed.has(i)) continue;
+ newSet.add(i);
+ if (typeof i !== "string") {
+ isTerminal = false;
+ }
+ }
+ }
+ }
+ }
+ if (newSet === true) {
+ innerGraph.set(key, true);
+ } else if (newSet.size === 0) {
+ innerGraph.set(key, undefined);
+ } else {
+ innerGraph.set(key, newSet);
+ }
+ }
+ if (isTerminal) {
+ nonTerminal.delete(key);
+
+ // For the global key, merge with all other keys
+ if (key === null) {
+ const globalValue = innerGraph.get(null);
+ if (globalValue) {
+ for (const [key, value] of innerGraph) {
+ if (key !== null && value !== true) {
+ if (globalValue === true) {
+ innerGraph.set(key, true);
+ } else {
+ const newSet = new Set(value);
+ for (const item of globalValue) {
+ newSet.add(item);
+ }
+ innerGraph.set(key, newSet);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /** @type {Map<Dependency, true | Set<string>>} */
+ for (const [symbol, callbacks] of usageCallbackMap) {
+ const usage = /** @type {true | Set<string> | undefined} */ (
+ innerGraph.get(symbol)
+ );
+ for (const callback of callbacks) {
+ callback(usage === undefined ? false : usage);
+ }
+ }
+};
+
+/**
+ * @param {ParserState} state parser state
+ * @param {UsageCallback} onUsageCallback on usage callback
+ */
+exports.onUsage = (state, onUsageCallback) => {
+ const innerGraphState = getState(state);
+
+ if (innerGraphState) {
+ const { usageCallbackMap, currentTopLevelSymbol } = innerGraphState;
+ if (currentTopLevelSymbol) {
+ let callbacks = usageCallbackMap.get(currentTopLevelSymbol);
+
+ if (callbacks === undefined) {
+ callbacks = new Set();
+ usageCallbackMap.set(currentTopLevelSymbol, callbacks);
+ }
+
+ callbacks.add(onUsageCallback);
+ } else {
+ onUsageCallback(true);
+ }
+ } else {
+ onUsageCallback(undefined);
+ }
+};
+
+/**
+ * @param {ParserState} state parser state
+ * @param {TopLevelSymbol | undefined} symbol the symbol
+ */
+exports.setTopLevelSymbol = (state, symbol) => {
+ const innerGraphState = getState(state);
+
+ if (innerGraphState) {
+ innerGraphState.currentTopLevelSymbol = symbol;
+ }
+};
+
+/**
+ * @param {ParserState} state parser state
+ * @returns {TopLevelSymbol|void} usage data
+ */
+exports.getTopLevelSymbol = state => {
+ const innerGraphState = getState(state);
+
+ if (innerGraphState) {
+ return innerGraphState.currentTopLevelSymbol;
+ }
+};
+
+/**
+ * @param {JavascriptParser} parser parser
+ * @param {string} name name of variable
+ * @returns {TopLevelSymbol | undefined} symbol
+ */
+exports.tagTopLevelSymbol = (parser, name) => {
+ const innerGraphState = getState(parser.state);
+ if (!innerGraphState) return;
+
+ parser.defineVariable(name);
+
+ const existingTag = /** @type {TopLevelSymbol} */ (
+ parser.getTagData(name, topLevelSymbolTag)
+ );
+ if (existingTag) {
+ return existingTag;
+ }
+
+ const fn = new TopLevelSymbol(name);
+ parser.tagVariable(name, topLevelSymbolTag, fn);
+ return fn;
+};
+
+/**
+ * @param {Dependency} dependency the dependency
+ * @param {Set<string> | boolean} usedByExports usedByExports info
+ * @param {ModuleGraph} moduleGraph moduleGraph
+ * @param {RuntimeSpec} runtime runtime
+ * @returns {boolean} false, when unused. Otherwise true
+ */
+exports.isDependencyUsedByExports = (
+ dependency,
+ usedByExports,
+ moduleGraph,
+ runtime
+) => {
+ if (usedByExports === false) return false;
+ if (usedByExports !== true && usedByExports !== undefined) {
+ const selfModule = moduleGraph.getParentModule(dependency);
+ const exportsInfo = moduleGraph.getExportsInfo(selfModule);
+ let used = false;
+ for (const exportName of usedByExports) {
+ if (exportsInfo.getUsed(exportName, runtime) !== UsageState.Unused)
+ used = true;
+ }
+ if (!used) return false;
+ }
+ return true;
+};
+
+/**
+ * @param {Dependency} dependency the dependency
+ * @param {Set<string> | boolean | undefined} usedByExports usedByExports info
+ * @param {ModuleGraph} moduleGraph moduleGraph
+ * @returns {null | false | function(ModuleGraphConnection, RuntimeSpec): ConnectionState} function to determine if the connection is active
+ */
+exports.getDependencyUsedByExportsCondition = (
+ dependency,
+ usedByExports,
+ moduleGraph
+) => {
+ if (usedByExports === false) return false;
+ if (usedByExports !== true && usedByExports !== undefined) {
+ const selfModule = moduleGraph.getParentModule(dependency);
+ const exportsInfo = moduleGraph.getExportsInfo(selfModule);
+ return (connections, runtime) => {
+ for (const exportName of usedByExports) {
+ if (exportsInfo.getUsed(exportName, runtime) !== UsageState.Unused)
+ return true;
+ }
+ return false;
+ };
+ }
+ return null;
+};
+
+class TopLevelSymbol {
+ /**
+ * @param {string} name name of the variable
+ */
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+exports.TopLevelSymbol = TopLevelSymbol;
+exports.topLevelSymbolTag = topLevelSymbolTag;
diff --git a/node_modules/webpack/lib/optimize/InnerGraphPlugin.js b/node_modules/webpack/lib/optimize/InnerGraphPlugin.js
new file mode 100644
index 00000000..f541030a
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/InnerGraphPlugin.js
@@ -0,0 +1,377 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const {
+ JAVASCRIPT_MODULE_TYPE_AUTO,
+ JAVASCRIPT_MODULE_TYPE_ESM
+} = require("../ModuleTypeConstants");
+const PureExpressionDependency = require("../dependencies/PureExpressionDependency");
+const InnerGraph = require("./InnerGraph");
+
+/** @typedef {import("estree").ClassDeclaration} ClassDeclarationNode */
+/** @typedef {import("estree").ClassExpression} ClassExpressionNode */
+/** @typedef {import("estree").Node} Node */
+/** @typedef {import("estree").VariableDeclarator} VariableDeclaratorNode */
+/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Dependency")} Dependency */
+/** @typedef {import("../dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
+/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
+/** @typedef {import("./InnerGraph").InnerGraph} InnerGraph */
+/** @typedef {import("./InnerGraph").TopLevelSymbol} TopLevelSymbol */
+
+const { topLevelSymbolTag } = InnerGraph;
+
+const PLUGIN_NAME = "InnerGraphPlugin";
+
+class InnerGraphPlugin {
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap(
+ PLUGIN_NAME,
+ (compilation, { normalModuleFactory }) => {
+ const logger = compilation.getLogger("webpack.InnerGraphPlugin");
+
+ compilation.dependencyTemplates.set(
+ PureExpressionDependency,
+ new PureExpressionDependency.Template()
+ );
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @param {JavascriptParserOptions} parserOptions options
+ * @returns {void}
+ */
+ const handler = (parser, parserOptions) => {
+ const onUsageSuper = sup => {
+ InnerGraph.onUsage(parser.state, usedByExports => {
+ switch (usedByExports) {
+ case undefined:
+ case true:
+ return;
+ default: {
+ const dep = new PureExpressionDependency(sup.range);
+ dep.loc = sup.loc;
+ dep.usedByExports = usedByExports;
+ parser.state.module.addDependency(dep);
+ break;
+ }
+ }
+ });
+ };
+
+ parser.hooks.program.tap(PLUGIN_NAME, () => {
+ InnerGraph.enable(parser.state);
+ });
+
+ parser.hooks.finish.tap(PLUGIN_NAME, () => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+
+ logger.time("infer dependency usage");
+ InnerGraph.inferDependencyUsage(parser.state);
+ logger.timeAggregate("infer dependency usage");
+ });
+
+ // During prewalking the following datastructures are filled with
+ // nodes that have a TopLevelSymbol assigned and
+ // variables are tagged with the assigned TopLevelSymbol
+
+ // We differ 3 types of nodes:
+ // 1. full statements (export default, function declaration)
+ // 2. classes (class declaration, class expression)
+ // 3. variable declarators (const x = ...)
+
+ /** @type {WeakMap<Node, TopLevelSymbol>} */
+ const statementWithTopLevelSymbol = new WeakMap();
+ /** @type {WeakMap<Node, Node>} */
+ const statementPurePart = new WeakMap();
+
+ /** @type {WeakMap<ClassExpressionNode | ClassDeclarationNode, TopLevelSymbol>} */
+ const classWithTopLevelSymbol = new WeakMap();
+
+ /** @type {WeakMap<VariableDeclaratorNode, TopLevelSymbol>} */
+ const declWithTopLevelSymbol = new WeakMap();
+ /** @type {WeakSet<VariableDeclaratorNode>} */
+ const pureDeclarators = new WeakSet();
+
+ // The following hooks are used during prewalking:
+
+ parser.hooks.preStatement.tap(PLUGIN_NAME, statement => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+
+ if (parser.scope.topLevelScope === true) {
+ if (statement.type === "FunctionDeclaration") {
+ const name = statement.id ? statement.id.name : "*default*";
+ const fn = InnerGraph.tagTopLevelSymbol(parser, name);
+ statementWithTopLevelSymbol.set(statement, fn);
+ return true;
+ }
+ }
+ });
+
+ parser.hooks.blockPreStatement.tap(PLUGIN_NAME, statement => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+
+ if (parser.scope.topLevelScope === true) {
+ if (
+ statement.type === "ClassDeclaration" &&
+ parser.isPure(statement, statement.range[0])
+ ) {
+ const name = statement.id ? statement.id.name : "*default*";
+ const fn = InnerGraph.tagTopLevelSymbol(parser, name);
+ classWithTopLevelSymbol.set(statement, fn);
+ return true;
+ }
+ if (statement.type === "ExportDefaultDeclaration") {
+ const name = "*default*";
+ const fn = InnerGraph.tagTopLevelSymbol(parser, name);
+ const decl = statement.declaration;
+ if (
+ (decl.type === "ClassExpression" ||
+ decl.type === "ClassDeclaration") &&
+ parser.isPure(decl, decl.range[0])
+ ) {
+ classWithTopLevelSymbol.set(decl, fn);
+ } else if (parser.isPure(decl, statement.range[0])) {
+ statementWithTopLevelSymbol.set(statement, fn);
+ if (
+ !decl.type.endsWith("FunctionExpression") &&
+ !decl.type.endsWith("Declaration") &&
+ decl.type !== "Literal"
+ ) {
+ statementPurePart.set(statement, decl);
+ }
+ }
+ }
+ }
+ });
+
+ parser.hooks.preDeclarator.tap(PLUGIN_NAME, (decl, statement) => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (
+ parser.scope.topLevelScope === true &&
+ decl.init &&
+ decl.id.type === "Identifier"
+ ) {
+ const name = decl.id.name;
+ if (
+ decl.init.type === "ClassExpression" &&
+ parser.isPure(decl.init, decl.id.range[1])
+ ) {
+ const fn = InnerGraph.tagTopLevelSymbol(parser, name);
+ classWithTopLevelSymbol.set(decl.init, fn);
+ } else if (parser.isPure(decl.init, decl.id.range[1])) {
+ const fn = InnerGraph.tagTopLevelSymbol(parser, name);
+ declWithTopLevelSymbol.set(decl, fn);
+ if (
+ !decl.init.type.endsWith("FunctionExpression") &&
+ decl.init.type !== "Literal"
+ ) {
+ pureDeclarators.add(decl);
+ }
+ return true;
+ }
+ }
+ });
+
+ // During real walking we set the TopLevelSymbol state to the assigned
+ // TopLevelSymbol by using the fill datastructures.
+
+ // In addition to tracking TopLevelSymbols, we sometimes need to
+ // add a PureExpressionDependency. This is needed to skip execution
+ // of pure expressions, even when they are not dropped due to
+ // minimizing. Otherwise symbols used there might not exist anymore
+ // as they are removed as unused by this optimization
+
+ // When we find a reference to a TopLevelSymbol, we register a
+ // TopLevelSymbol dependency from TopLevelSymbol in state to the
+ // referenced TopLevelSymbol. This way we get a graph of all
+ // TopLevelSymbols.
+
+ // The following hooks are called during walking:
+
+ parser.hooks.statement.tap(PLUGIN_NAME, statement => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (parser.scope.topLevelScope === true) {
+ InnerGraph.setTopLevelSymbol(parser.state, undefined);
+
+ const fn = statementWithTopLevelSymbol.get(statement);
+ if (fn) {
+ InnerGraph.setTopLevelSymbol(parser.state, fn);
+ const purePart = statementPurePart.get(statement);
+ if (purePart) {
+ InnerGraph.onUsage(parser.state, usedByExports => {
+ switch (usedByExports) {
+ case undefined:
+ case true:
+ return;
+ default: {
+ const dep = new PureExpressionDependency(
+ purePart.range
+ );
+ dep.loc = statement.loc;
+ dep.usedByExports = usedByExports;
+ parser.state.module.addDependency(dep);
+ break;
+ }
+ }
+ });
+ }
+ }
+ }
+ });
+
+ parser.hooks.classExtendsExpression.tap(
+ PLUGIN_NAME,
+ (expr, statement) => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (parser.scope.topLevelScope === true) {
+ const fn = classWithTopLevelSymbol.get(statement);
+ if (
+ fn &&
+ parser.isPure(
+ expr,
+ statement.id ? statement.id.range[1] : statement.range[0]
+ )
+ ) {
+ InnerGraph.setTopLevelSymbol(parser.state, fn);
+ onUsageSuper(expr);
+ }
+ }
+ }
+ );
+
+ parser.hooks.classBodyElement.tap(
+ PLUGIN_NAME,
+ (element, classDefinition) => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (parser.scope.topLevelScope === true) {
+ const fn = classWithTopLevelSymbol.get(classDefinition);
+ if (fn) {
+ InnerGraph.setTopLevelSymbol(parser.state, undefined);
+ }
+ }
+ }
+ );
+
+ parser.hooks.classBodyValue.tap(
+ PLUGIN_NAME,
+ (expression, element, classDefinition) => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (parser.scope.topLevelScope === true) {
+ const fn = classWithTopLevelSymbol.get(classDefinition);
+ if (fn) {
+ if (
+ !element.static ||
+ parser.isPure(
+ expression,
+ element.key ? element.key.range[1] : element.range[0]
+ )
+ ) {
+ InnerGraph.setTopLevelSymbol(parser.state, fn);
+ if (element.type !== "MethodDefinition" && element.static) {
+ InnerGraph.onUsage(parser.state, usedByExports => {
+ switch (usedByExports) {
+ case undefined:
+ case true:
+ return;
+ default: {
+ const dep = new PureExpressionDependency(
+ expression.range
+ );
+ dep.loc = expression.loc;
+ dep.usedByExports = usedByExports;
+ parser.state.module.addDependency(dep);
+ break;
+ }
+ }
+ });
+ }
+ } else {
+ InnerGraph.setTopLevelSymbol(parser.state, undefined);
+ }
+ }
+ }
+ }
+ );
+
+ parser.hooks.declarator.tap(PLUGIN_NAME, (decl, statement) => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ const fn = declWithTopLevelSymbol.get(decl);
+
+ if (fn) {
+ InnerGraph.setTopLevelSymbol(parser.state, fn);
+ if (pureDeclarators.has(decl)) {
+ if (decl.init.type === "ClassExpression") {
+ if (decl.init.superClass) {
+ onUsageSuper(decl.init.superClass);
+ }
+ } else {
+ InnerGraph.onUsage(parser.state, usedByExports => {
+ switch (usedByExports) {
+ case undefined:
+ case true:
+ return;
+ default: {
+ const dep = new PureExpressionDependency(
+ decl.init.range
+ );
+ dep.loc = decl.loc;
+ dep.usedByExports = usedByExports;
+ parser.state.module.addDependency(dep);
+ break;
+ }
+ }
+ });
+ }
+ }
+ parser.walkExpression(decl.init);
+ InnerGraph.setTopLevelSymbol(parser.state, undefined);
+ return true;
+ }
+ });
+
+ parser.hooks.expression
+ .for(topLevelSymbolTag)
+ .tap(PLUGIN_NAME, () => {
+ const topLevelSymbol = /** @type {TopLevelSymbol} */ (
+ parser.currentTagData
+ );
+ const currentTopLevelSymbol = InnerGraph.getTopLevelSymbol(
+ parser.state
+ );
+ InnerGraph.addUsage(
+ parser.state,
+ topLevelSymbol,
+ currentTopLevelSymbol || true
+ );
+ });
+ parser.hooks.assign.for(topLevelSymbolTag).tap(PLUGIN_NAME, expr => {
+ if (!InnerGraph.isEnabled(parser.state)) return;
+ if (expr.operator === "=") return true;
+ });
+ };
+ normalModuleFactory.hooks.parser
+ .for(JAVASCRIPT_MODULE_TYPE_AUTO)
+ .tap(PLUGIN_NAME, handler);
+ normalModuleFactory.hooks.parser
+ .for(JAVASCRIPT_MODULE_TYPE_ESM)
+ .tap(PLUGIN_NAME, handler);
+
+ compilation.hooks.finishModules.tap(PLUGIN_NAME, () => {
+ logger.timeAggregateEnd("infer dependency usage");
+ });
+ }
+ );
+ }
+}
+
+module.exports = InnerGraphPlugin;
diff --git a/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js
new file mode 100644
index 00000000..445719b6
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js
@@ -0,0 +1,281 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_ADVANCED } = require("../OptimizationStages");
+const LazyBucketSortedSet = require("../util/LazyBucketSortedSet");
+const { compareChunks } = require("../util/comparators");
+const createSchemaValidation = require("../util/create-schema-validation");
+
+/** @typedef {import("../../declarations/plugins/optimize/LimitChunkCountPlugin").LimitChunkCountPluginOptions} LimitChunkCountPluginOptions */
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../Compiler")} Compiler */
+
+const validate = createSchemaValidation(
+ require("../../schemas/plugins/optimize/LimitChunkCountPlugin.check.js"),
+ () => require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json"),
+ {
+ name: "Limit Chunk Count Plugin",
+ baseDataPath: "options"
+ }
+);
+
+/**
+ * @typedef {Object} ChunkCombination
+ * @property {boolean} deleted this is set to true when combination was removed
+ * @property {number} sizeDiff
+ * @property {number} integratedSize
+ * @property {Chunk} a
+ * @property {Chunk} b
+ * @property {number} aIdx
+ * @property {number} bIdx
+ * @property {number} aSize
+ * @property {number} bSize
+ */
+
+/**
+ * @template K, V
+ * @param {Map<K, Set<V>>} map map
+ * @param {K} key key
+ * @param {V} value value
+ */
+const addToSetMap = (map, key, value) => {
+ const set = map.get(key);
+ if (set === undefined) {
+ map.set(key, new Set([value]));
+ } else {
+ set.add(value);
+ }
+};
+
+class LimitChunkCountPlugin {
+ /**
+ * @param {LimitChunkCountPluginOptions=} options options object
+ */
+ constructor(options) {
+ validate(options);
+ this.options = options;
+ }
+
+ /**
+ * @param {Compiler} compiler the webpack compiler
+ * @returns {void}
+ */
+ apply(compiler) {
+ const options = this.options;
+ compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "LimitChunkCountPlugin",
+ stage: STAGE_ADVANCED
+ },
+ chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ const maxChunks =
+ /** @type {LimitChunkCountPluginOptions} */
+ (options).maxChunks;
+ if (!maxChunks) return;
+ if (maxChunks < 1) return;
+ if (compilation.chunks.size <= maxChunks) return;
+
+ let remainingChunksToMerge = compilation.chunks.size - maxChunks;
+
+ // order chunks in a deterministic way
+ const compareChunksWithGraph = compareChunks(chunkGraph);
+ const orderedChunks = Array.from(chunks).sort(compareChunksWithGraph);
+
+ // create a lazy sorted data structure to keep all combinations
+ // this is large. Size = chunks * (chunks - 1) / 2
+ // It uses a multi layer bucket sort plus normal sort in the last layer
+ // It's also lazy so only accessed buckets are sorted
+ const combinations = new LazyBucketSortedSet(
+ // Layer 1: ordered by largest size benefit
+ c => c.sizeDiff,
+ (a, b) => b - a,
+ // Layer 2: ordered by smallest combined size
+ /**
+ * @param {ChunkCombination} c combination
+ * @returns {number} integrated size
+ */
+ c => c.integratedSize,
+ (a, b) => a - b,
+ // Layer 3: ordered by position difference in orderedChunk (-> to be deterministic)
+ /**
+ * @param {ChunkCombination} c combination
+ * @returns {number} position difference
+ */
+ c => c.bIdx - c.aIdx,
+ (a, b) => a - b,
+ // Layer 4: ordered by position in orderedChunk (-> to be deterministic)
+ (a, b) => a.bIdx - b.bIdx
+ );
+
+ // we keep a mapping from chunk to all combinations
+ // but this mapping is not kept up-to-date with deletions
+ // so `deleted` flag need to be considered when iterating this
+ /** @type {Map<Chunk, Set<ChunkCombination>>} */
+ const combinationsByChunk = new Map();
+
+ orderedChunks.forEach((b, bIdx) => {
+ // create combination pairs with size and integrated size
+ for (let aIdx = 0; aIdx < bIdx; aIdx++) {
+ const a = orderedChunks[aIdx];
+ // filter pairs that can not be integrated!
+ if (!chunkGraph.canChunksBeIntegrated(a, b)) continue;
+
+ const integratedSize = chunkGraph.getIntegratedChunksSize(
+ a,
+ b,
+ options
+ );
+
+ const aSize = chunkGraph.getChunkSize(a, options);
+ const bSize = chunkGraph.getChunkSize(b, options);
+ const c = {
+ deleted: false,
+ sizeDiff: aSize + bSize - integratedSize,
+ integratedSize,
+ a,
+ b,
+ aIdx,
+ bIdx,
+ aSize,
+ bSize
+ };
+ combinations.add(c);
+ addToSetMap(combinationsByChunk, a, c);
+ addToSetMap(combinationsByChunk, b, c);
+ }
+ return combinations;
+ });
+
+ // list of modified chunks during this run
+ // combinations affected by this change are skipped to allow
+ // further optimizations
+ /** @type {Set<Chunk>} */
+ const modifiedChunks = new Set();
+
+ let changed = false;
+ // eslint-disable-next-line no-constant-condition
+ loop: while (true) {
+ const combination = combinations.popFirst();
+ if (combination === undefined) break;
+
+ combination.deleted = true;
+ const { a, b, integratedSize } = combination;
+
+ // skip over pair when
+ // one of the already merged chunks is a parent of one of the chunks
+ if (modifiedChunks.size > 0) {
+ const queue = new Set(a.groupsIterable);
+ for (const group of b.groupsIterable) {
+ queue.add(group);
+ }
+ for (const group of queue) {
+ for (const mChunk of modifiedChunks) {
+ if (mChunk !== a && mChunk !== b && mChunk.isInGroup(group)) {
+ // This is a potential pair which needs recalculation
+ // We can't do that now, but it merge before following pairs
+ // so we leave space for it, and consider chunks as modified
+ // just for the worse case
+ remainingChunksToMerge--;
+ if (remainingChunksToMerge <= 0) break loop;
+ modifiedChunks.add(a);
+ modifiedChunks.add(b);
+ continue loop;
+ }
+ }
+ for (const parent of group.parentsIterable) {
+ queue.add(parent);
+ }
+ }
+ }
+
+ // merge the chunks
+ if (chunkGraph.canChunksBeIntegrated(a, b)) {
+ chunkGraph.integrateChunks(a, b);
+ compilation.chunks.delete(b);
+
+ // flag chunk a as modified as further optimization are possible for all children here
+ modifiedChunks.add(a);
+
+ changed = true;
+ remainingChunksToMerge--;
+ if (remainingChunksToMerge <= 0) break;
+
+ // Update all affected combinations
+ // delete all combination with the removed chunk
+ // we will use combinations with the kept chunk instead
+ for (const combination of /** @type {Set<ChunkCombination>} */ (
+ combinationsByChunk.get(a)
+ )) {
+ if (combination.deleted) continue;
+ combination.deleted = true;
+ combinations.delete(combination);
+ }
+
+ // Update combinations with the kept chunk with new sizes
+ for (const combination of /** @type {Set<ChunkCombination>} */ (
+ combinationsByChunk.get(b)
+ )) {
+ if (combination.deleted) continue;
+ if (combination.a === b) {
+ if (!chunkGraph.canChunksBeIntegrated(a, combination.b)) {
+ combination.deleted = true;
+ combinations.delete(combination);
+ continue;
+ }
+ // Update size
+ const newIntegratedSize = chunkGraph.getIntegratedChunksSize(
+ a,
+ combination.b,
+ options
+ );
+ const finishUpdate = combinations.startUpdate(combination);
+ combination.a = a;
+ combination.integratedSize = newIntegratedSize;
+ combination.aSize = integratedSize;
+ combination.sizeDiff =
+ combination.bSize + integratedSize - newIntegratedSize;
+ finishUpdate();
+ } else if (combination.b === b) {
+ if (!chunkGraph.canChunksBeIntegrated(combination.a, a)) {
+ combination.deleted = true;
+ combinations.delete(combination);
+ continue;
+ }
+ // Update size
+ const newIntegratedSize = chunkGraph.getIntegratedChunksSize(
+ combination.a,
+ a,
+ options
+ );
+
+ const finishUpdate = combinations.startUpdate(combination);
+ combination.b = a;
+ combination.integratedSize = newIntegratedSize;
+ combination.bSize = integratedSize;
+ combination.sizeDiff =
+ integratedSize + combination.aSize - newIntegratedSize;
+ finishUpdate();
+ }
+ }
+ combinationsByChunk.set(
+ a,
+ /** @type {Set<ChunkCombination>} */ (
+ combinationsByChunk.get(b)
+ )
+ );
+ combinationsByChunk.delete(b);
+ }
+ }
+ if (changed) return true;
+ }
+ );
+ });
+ }
+}
+module.exports = LimitChunkCountPlugin;
diff --git a/node_modules/webpack/lib/optimize/MangleExportsPlugin.js b/node_modules/webpack/lib/optimize/MangleExportsPlugin.js
new file mode 100644
index 00000000..30884448
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/MangleExportsPlugin.js
@@ -0,0 +1,177 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { UsageState } = require("../ExportsInfo");
+const {
+ numberToIdentifier,
+ NUMBER_OF_IDENTIFIER_START_CHARS,
+ NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS
+} = require("../Template");
+const { assignDeterministicIds } = require("../ids/IdHelpers");
+const { compareSelect, compareStringsNumeric } = require("../util/comparators");
+
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../ExportsInfo")} ExportsInfo */
+/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
+
+/**
+ * @param {ExportsInfo} exportsInfo exports info
+ * @returns {boolean} mangle is possible
+ */
+const canMangle = exportsInfo => {
+ if (exportsInfo.otherExportsInfo.getUsed(undefined) !== UsageState.Unused)
+ return false;
+ let hasSomethingToMangle = false;
+ for (const exportInfo of exportsInfo.exports) {
+ if (exportInfo.canMangle === true) {
+ hasSomethingToMangle = true;
+ }
+ }
+ return hasSomethingToMangle;
+};
+
+// Sort by name
+const comparator = compareSelect(e => e.name, compareStringsNumeric);
+/**
+ * @param {boolean} deterministic use deterministic names
+ * @param {ExportsInfo} exportsInfo exports info
+ * @param {boolean | undefined} isNamespace is namespace object
+ * @returns {void}
+ */
+const mangleExportsInfo = (deterministic, exportsInfo, isNamespace) => {
+ if (!canMangle(exportsInfo)) return;
+ const usedNames = new Set();
+ /** @type {ExportInfo[]} */
+ const mangleableExports = [];
+
+ // Avoid to renamed exports that are not provided when
+ // 1. it's not a namespace export: non-provided exports can be found in prototype chain
+ // 2. there are other provided exports and deterministic mode is chosen:
+ // non-provided exports would break the determinism
+ let avoidMangleNonProvided = !isNamespace;
+ if (!avoidMangleNonProvided && deterministic) {
+ for (const exportInfo of exportsInfo.ownedExports) {
+ if (exportInfo.provided !== false) {
+ avoidMangleNonProvided = true;
+ break;
+ }
+ }
+ }
+ for (const exportInfo of exportsInfo.ownedExports) {
+ const name = exportInfo.name;
+ if (!exportInfo.hasUsedName()) {
+ if (
+ // Can the export be mangled?
+ exportInfo.canMangle !== true ||
+ // Never rename 1 char exports
+ (name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) ||
+ // Don't rename 2 char exports in deterministic mode
+ (deterministic &&
+ name.length === 2 &&
+ /^[a-zA-Z_$][a-zA-Z0-9_$]|^[1-9][0-9]/.test(name)) ||
+ // Don't rename exports that are not provided
+ (avoidMangleNonProvided && exportInfo.provided !== true)
+ ) {
+ exportInfo.setUsedName(name);
+ usedNames.add(name);
+ } else {
+ mangleableExports.push(exportInfo);
+ }
+ }
+ if (exportInfo.exportsInfoOwned) {
+ const used = exportInfo.getUsed(undefined);
+ if (
+ used === UsageState.OnlyPropertiesUsed ||
+ used === UsageState.Unused
+ ) {
+ mangleExportsInfo(deterministic, exportInfo.exportsInfo, false);
+ }
+ }
+ }
+ if (deterministic) {
+ assignDeterministicIds(
+ mangleableExports,
+ e => e.name,
+ comparator,
+ (e, id) => {
+ const name = numberToIdentifier(id);
+ const size = usedNames.size;
+ usedNames.add(name);
+ if (size === usedNames.size) return false;
+ e.setUsedName(name);
+ return true;
+ },
+ [
+ NUMBER_OF_IDENTIFIER_START_CHARS,
+ NUMBER_OF_IDENTIFIER_START_CHARS *
+ NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS
+ ],
+ NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS,
+ usedNames.size
+ );
+ } else {
+ const usedExports = [];
+ const unusedExports = [];
+ for (const exportInfo of mangleableExports) {
+ if (exportInfo.getUsed(undefined) === UsageState.Unused) {
+ unusedExports.push(exportInfo);
+ } else {
+ usedExports.push(exportInfo);
+ }
+ }
+ usedExports.sort(comparator);
+ unusedExports.sort(comparator);
+ let i = 0;
+ for (const list of [usedExports, unusedExports]) {
+ for (const exportInfo of list) {
+ let name;
+ do {
+ name = numberToIdentifier(i++);
+ } while (usedNames.has(name));
+ exportInfo.setUsedName(name);
+ }
+ }
+ }
+};
+
+class MangleExportsPlugin {
+ /**
+ * @param {boolean} deterministic use deterministic names
+ */
+ constructor(deterministic) {
+ this._deterministic = deterministic;
+ }
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ const { _deterministic: deterministic } = this;
+ compiler.hooks.compilation.tap("MangleExportsPlugin", compilation => {
+ const moduleGraph = compilation.moduleGraph;
+ compilation.hooks.optimizeCodeGeneration.tap(
+ "MangleExportsPlugin",
+ modules => {
+ if (compilation.moduleMemCaches) {
+ throw new Error(
+ "optimization.mangleExports can't be used with cacheUnaffected as export mangling is a global effect"
+ );
+ }
+ for (const module of modules) {
+ const isNamespace =
+ module.buildMeta && module.buildMeta.exportsType === "namespace";
+ const exportsInfo = moduleGraph.getExportsInfo(module);
+ mangleExportsInfo(deterministic, exportsInfo, isNamespace);
+ }
+ }
+ );
+ });
+ }
+}
+
+module.exports = MangleExportsPlugin;
diff --git a/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js
new file mode 100644
index 00000000..76cc2479
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js
@@ -0,0 +1,115 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_BASIC } = require("../OptimizationStages");
+const { runtimeEqual } = require("../util/runtime");
+
+/** @typedef {import("../Compiler")} Compiler */
+
+class MergeDuplicateChunksPlugin {
+ /**
+ * @param {Compiler} compiler the compiler
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap(
+ "MergeDuplicateChunksPlugin",
+ compilation => {
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "MergeDuplicateChunksPlugin",
+ stage: STAGE_BASIC
+ },
+ chunks => {
+ const { chunkGraph, moduleGraph } = compilation;
+
+ // remember already tested chunks for performance
+ const notDuplicates = new Set();
+
+ // for each chunk
+ for (const chunk of chunks) {
+ // track a Set of all chunk that could be duplicates
+ let possibleDuplicates;
+ for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
+ if (possibleDuplicates === undefined) {
+ // when possibleDuplicates is not yet set,
+ // create a new Set from chunks of the current module
+ // including only chunks with the same number of modules
+ for (const dup of chunkGraph.getModuleChunksIterable(
+ module
+ )) {
+ if (
+ dup !== chunk &&
+ chunkGraph.getNumberOfChunkModules(chunk) ===
+ chunkGraph.getNumberOfChunkModules(dup) &&
+ !notDuplicates.has(dup)
+ ) {
+ // delay allocating the new Set until here, reduce memory pressure
+ if (possibleDuplicates === undefined) {
+ possibleDuplicates = new Set();
+ }
+ possibleDuplicates.add(dup);
+ }
+ }
+ // when no chunk is possible we can break here
+ if (possibleDuplicates === undefined) break;
+ } else {
+ // validate existing possible duplicates
+ for (const dup of possibleDuplicates) {
+ // remove possible duplicate when module is not contained
+ if (!chunkGraph.isModuleInChunk(module, dup)) {
+ possibleDuplicates.delete(dup);
+ }
+ }
+ // when all chunks has been removed we can break here
+ if (possibleDuplicates.size === 0) break;
+ }
+ }
+
+ // when we found duplicates
+ if (
+ possibleDuplicates !== undefined &&
+ possibleDuplicates.size > 0
+ ) {
+ outer: for (const otherChunk of possibleDuplicates) {
+ if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;
+ if (chunkGraph.getNumberOfEntryModules(chunk) > 0) continue;
+ if (chunkGraph.getNumberOfEntryModules(otherChunk) > 0)
+ continue;
+ if (!runtimeEqual(chunk.runtime, otherChunk.runtime)) {
+ for (const module of chunkGraph.getChunkModulesIterable(
+ chunk
+ )) {
+ const exportsInfo = moduleGraph.getExportsInfo(module);
+ if (
+ !exportsInfo.isEquallyUsed(
+ chunk.runtime,
+ otherChunk.runtime
+ )
+ ) {
+ continue outer;
+ }
+ }
+ }
+ // merge them
+ if (chunkGraph.canChunksBeIntegrated(chunk, otherChunk)) {
+ chunkGraph.integrateChunks(chunk, otherChunk);
+ compilation.chunks.delete(otherChunk);
+ }
+ }
+ }
+
+ // don't check already processed chunks twice
+ notDuplicates.add(chunk);
+ }
+ }
+ );
+ }
+ );
+ }
+}
+module.exports = MergeDuplicateChunksPlugin;
diff --git a/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js
new file mode 100644
index 00000000..b51164c2
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js
@@ -0,0 +1,113 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_ADVANCED } = require("../OptimizationStages");
+const createSchemaValidation = require("../util/create-schema-validation");
+
+/** @typedef {import("../../declarations/plugins/optimize/MinChunkSizePlugin").MinChunkSizePluginOptions} MinChunkSizePluginOptions */
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../Compiler")} Compiler */
+
+const validate = createSchemaValidation(
+ require("../../schemas/plugins/optimize/MinChunkSizePlugin.check.js"),
+ () => require("../../schemas/plugins/optimize/MinChunkSizePlugin.json"),
+ {
+ name: "Min Chunk Size Plugin",
+ baseDataPath: "options"
+ }
+);
+
+class MinChunkSizePlugin {
+ /**
+ * @param {MinChunkSizePluginOptions} options options object
+ */
+ constructor(options) {
+ validate(options);
+ this.options = options;
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ const options = this.options;
+ const minChunkSize = options.minChunkSize;
+ compiler.hooks.compilation.tap("MinChunkSizePlugin", compilation => {
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "MinChunkSizePlugin",
+ stage: STAGE_ADVANCED
+ },
+ chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ const equalOptions = {
+ chunkOverhead: 1,
+ entryChunkMultiplicator: 1
+ };
+
+ const chunkSizesMap = new Map();
+ /** @type {[Chunk, Chunk][]} */
+ const combinations = [];
+ /** @type {Chunk[]} */
+ const smallChunks = [];
+ const visitedChunks = [];
+ for (const a of chunks) {
+ // check if one of the chunks sizes is smaller than the minChunkSize
+ // and filter pairs that can NOT be integrated!
+ if (chunkGraph.getChunkSize(a, equalOptions) < minChunkSize) {
+ smallChunks.push(a);
+ for (const b of visitedChunks) {
+ if (chunkGraph.canChunksBeIntegrated(b, a))
+ combinations.push([b, a]);
+ }
+ } else {
+ for (const b of smallChunks) {
+ if (chunkGraph.canChunksBeIntegrated(b, a))
+ combinations.push([b, a]);
+ }
+ }
+ chunkSizesMap.set(a, chunkGraph.getChunkSize(a, options));
+ visitedChunks.push(a);
+ }
+
+ const sortedSizeFilteredExtendedPairCombinations = combinations
+ .map(pair => {
+ // extend combination pairs with size and integrated size
+ const a = chunkSizesMap.get(pair[0]);
+ const b = chunkSizesMap.get(pair[1]);
+ const ab = chunkGraph.getIntegratedChunksSize(
+ pair[0],
+ pair[1],
+ options
+ );
+ /** @type {[number, number, Chunk, Chunk]} */
+ const extendedPair = [a + b - ab, ab, pair[0], pair[1]];
+ return extendedPair;
+ })
+ .sort((a, b) => {
+ // sadly javascript does an in place sort here
+ // sort by size
+ const diff = b[0] - a[0];
+ if (diff !== 0) return diff;
+ return a[1] - b[1];
+ });
+
+ if (sortedSizeFilteredExtendedPairCombinations.length === 0) return;
+
+ const pair = sortedSizeFilteredExtendedPairCombinations[0];
+
+ chunkGraph.integrateChunks(pair[2], pair[3]);
+ compilation.chunks.delete(pair[3]);
+ return true;
+ }
+ );
+ });
+ }
+}
+module.exports = MinChunkSizePlugin;
diff --git a/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js b/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js
new file mode 100644
index 00000000..42edd946
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js
@@ -0,0 +1,35 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const SizeFormatHelpers = require("../SizeFormatHelpers");
+const WebpackError = require("../WebpackError");
+
+class MinMaxSizeWarning extends WebpackError {
+ /**
+ * @param {string[] | undefined} keys keys
+ * @param {number} minSize minimum size
+ * @param {number} maxSize maximum size
+ */
+ constructor(keys, minSize, maxSize) {
+ let keysMessage = "Fallback cache group";
+ if (keys) {
+ keysMessage =
+ keys.length > 1
+ ? `Cache groups ${keys.sort().join(", ")}`
+ : `Cache group ${keys[0]}`;
+ }
+ super(
+ `SplitChunksPlugin\n` +
+ `${keysMessage}\n` +
+ `Configured minSize (${SizeFormatHelpers.formatSize(minSize)}) is ` +
+ `bigger than maxSize (${SizeFormatHelpers.formatSize(maxSize)}).\n` +
+ "This seem to be a invalid optimization.splitChunks configuration."
+ );
+ }
+}
+
+module.exports = MinMaxSizeWarning;
diff --git a/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js
new file mode 100644
index 00000000..7b0adfa8
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js
@@ -0,0 +1,942 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const asyncLib = require("neo-async");
+const ChunkGraph = require("../ChunkGraph");
+const ModuleGraph = require("../ModuleGraph");
+const { STAGE_DEFAULT } = require("../OptimizationStages");
+const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
+const { compareModulesByIdentifier } = require("../util/comparators");
+const {
+ intersectRuntime,
+ mergeRuntimeOwned,
+ filterRuntime,
+ runtimeToString,
+ mergeRuntime
+} = require("../util/runtime");
+const ConcatenatedModule = require("./ConcatenatedModule");
+
+/** @typedef {import("../Compilation")} Compilation */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Module")} Module */
+/** @typedef {import("../RequestShortener")} RequestShortener */
+/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
+
+/**
+ * @typedef {Object} Statistics
+ * @property {number} cached
+ * @property {number} alreadyInConfig
+ * @property {number} invalidModule
+ * @property {number} incorrectChunks
+ * @property {number} incorrectDependency
+ * @property {number} incorrectModuleDependency
+ * @property {number} incorrectChunksOfImporter
+ * @property {number} incorrectRuntimeCondition
+ * @property {number} importerFailed
+ * @property {number} added
+ */
+
+/**
+ * @param {string} msg message
+ * @returns {string} formatted message
+ */
+const formatBailoutReason = msg => {
+ return "ModuleConcatenation bailout: " + msg;
+};
+
+class ModuleConcatenationPlugin {
+ constructor(options) {
+ if (typeof options !== "object") options = {};
+ this.options = options;
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ const { _backCompat: backCompat } = compiler;
+ compiler.hooks.compilation.tap("ModuleConcatenationPlugin", compilation => {
+ if (compilation.moduleMemCaches) {
+ throw new Error(
+ "optimization.concatenateModules can't be used with cacheUnaffected as module concatenation is a global effect"
+ );
+ }
+ const moduleGraph = compilation.moduleGraph;
+ /** @type {Map<Module, string | ((requestShortener: RequestShortener) => string)>} */
+ const bailoutReasonMap = new Map();
+
+ /**
+ * @param {Module} module the module
+ * @param {string | ((requestShortener: RequestShortener) => string)} reason the reason
+ */
+ const setBailoutReason = (module, reason) => {
+ setInnerBailoutReason(module, reason);
+ moduleGraph
+ .getOptimizationBailout(module)
+ .push(
+ typeof reason === "function"
+ ? rs => formatBailoutReason(reason(rs))
+ : formatBailoutReason(reason)
+ );
+ };
+
+ /**
+ * @param {Module} module the module
+ * @param {string | ((requestShortener: RequestShortener) => string)} reason the reason
+ */
+ const setInnerBailoutReason = (module, reason) => {
+ bailoutReasonMap.set(module, reason);
+ };
+
+ /**
+ * @param {Module} module the module
+ * @param {RequestShortener} requestShortener the request shortener
+ * @returns {string | ((requestShortener: RequestShortener) => string) | undefined} the reason
+ */
+ const getInnerBailoutReason = (module, requestShortener) => {
+ const reason = bailoutReasonMap.get(module);
+ if (typeof reason === "function") return reason(requestShortener);
+ return reason;
+ };
+
+ /**
+ * @param {Module} module the module
+ * @param {Module | function(RequestShortener): string} problem the problem
+ * @returns {(requestShortener: RequestShortener) => string} the reason
+ */
+ const formatBailoutWarning = (module, problem) => requestShortener => {
+ if (typeof problem === "function") {
+ return formatBailoutReason(
+ `Cannot concat with ${module.readableIdentifier(
+ requestShortener
+ )}: ${problem(requestShortener)}`
+ );
+ }
+ const reason = getInnerBailoutReason(module, requestShortener);
+ const reasonWithPrefix = reason ? `: ${reason}` : "";
+ if (module === problem) {
+ return formatBailoutReason(
+ `Cannot concat with ${module.readableIdentifier(
+ requestShortener
+ )}${reasonWithPrefix}`
+ );
+ } else {
+ return formatBailoutReason(
+ `Cannot concat with ${module.readableIdentifier(
+ requestShortener
+ )} because of ${problem.readableIdentifier(
+ requestShortener
+ )}${reasonWithPrefix}`
+ );
+ }
+ };
+
+ compilation.hooks.optimizeChunkModules.tapAsync(
+ {
+ name: "ModuleConcatenationPlugin",
+ stage: STAGE_DEFAULT
+ },
+ (allChunks, modules, callback) => {
+ const logger = compilation.getLogger(
+ "webpack.ModuleConcatenationPlugin"
+ );
+ const { chunkGraph, moduleGraph } = compilation;
+ const relevantModules = [];
+ const possibleInners = new Set();
+ const context = {
+ chunkGraph,
+ moduleGraph
+ };
+ logger.time("select relevant modules");
+ for (const module of modules) {
+ let canBeRoot = true;
+ let canBeInner = true;
+
+ const bailoutReason = module.getConcatenationBailoutReason(context);
+ if (bailoutReason) {
+ setBailoutReason(module, bailoutReason);
+ continue;
+ }
+
+ // Must not be an async module
+ if (moduleGraph.isAsync(module)) {
+ setBailoutReason(module, `Module is async`);
+ continue;
+ }
+
+ // Must be in strict mode
+ if (!module.buildInfo.strict) {
+ setBailoutReason(module, `Module is not in strict mode`);
+ continue;
+ }
+
+ // Module must be in any chunk (we don't want to do useless work)
+ if (chunkGraph.getNumberOfModuleChunks(module) === 0) {
+ setBailoutReason(module, "Module is not in any chunk");
+ continue;
+ }
+
+ // Exports must be known (and not dynamic)
+ const exportsInfo = moduleGraph.getExportsInfo(module);
+ const relevantExports = exportsInfo.getRelevantExports(undefined);
+ const unknownReexports = relevantExports.filter(exportInfo => {
+ return (
+ exportInfo.isReexport() && !exportInfo.getTarget(moduleGraph)
+ );
+ });
+ if (unknownReexports.length > 0) {
+ setBailoutReason(
+ module,
+ `Reexports in this module do not have a static target (${Array.from(
+ unknownReexports,
+ exportInfo =>
+ `${
+ exportInfo.name || "other exports"
+ }: ${exportInfo.getUsedInfo()}`
+ ).join(", ")})`
+ );
+ continue;
+ }
+
+ // Root modules must have a static list of exports
+ const unknownProvidedExports = relevantExports.filter(
+ exportInfo => {
+ return exportInfo.provided !== true;
+ }
+ );
+ if (unknownProvidedExports.length > 0) {
+ setBailoutReason(
+ module,
+ `List of module exports is dynamic (${Array.from(
+ unknownProvidedExports,
+ exportInfo =>
+ `${
+ exportInfo.name || "other exports"
+ }: ${exportInfo.getProvidedInfo()} and ${exportInfo.getUsedInfo()}`
+ ).join(", ")})`
+ );
+ canBeRoot = false;
+ }
+
+ // Module must not be an entry point
+ if (chunkGraph.isEntryModule(module)) {
+ setInnerBailoutReason(module, "Module is an entry point");
+ canBeInner = false;
+ }
+
+ if (canBeRoot) relevantModules.push(module);
+ if (canBeInner) possibleInners.add(module);
+ }
+ logger.timeEnd("select relevant modules");
+ logger.debug(
+ `${relevantModules.length} potential root modules, ${possibleInners.size} potential inner modules`
+ );
+ // sort by depth
+ // modules with lower depth are more likely suited as roots
+ // this improves performance, because modules already selected as inner are skipped
+ logger.time("sort relevant modules");
+ relevantModules.sort((a, b) => {
+ return moduleGraph.getDepth(a) - moduleGraph.getDepth(b);
+ });
+ logger.timeEnd("sort relevant modules");
+
+ /** @type {Statistics} */
+ const stats = {
+ cached: 0,
+ alreadyInConfig: 0,
+ invalidModule: 0,
+ incorrectChunks: 0,
+ incorrectDependency: 0,
+ incorrectModuleDependency: 0,
+ incorrectChunksOfImporter: 0,
+ incorrectRuntimeCondition: 0,
+ importerFailed: 0,
+ added: 0
+ };
+ let statsCandidates = 0;
+ let statsSizeSum = 0;
+ let statsEmptyConfigurations = 0;
+
+ logger.time("find modules to concatenate");
+ const concatConfigurations = [];
+ const usedAsInner = new Set();
+ for (const currentRoot of relevantModules) {
+ // when used by another configuration as inner:
+ // the other configuration is better and we can skip this one
+ // TODO reconsider that when it's only used in a different runtime
+ if (usedAsInner.has(currentRoot)) continue;
+
+ let chunkRuntime = undefined;
+ for (const r of chunkGraph.getModuleRuntimes(currentRoot)) {
+ chunkRuntime = mergeRuntimeOwned(chunkRuntime, r);
+ }
+ const exportsInfo = moduleGraph.getExportsInfo(currentRoot);
+ const filteredRuntime = filterRuntime(chunkRuntime, r =>
+ exportsInfo.isModuleUsed(r)
+ );
+ const activeRuntime =
+ filteredRuntime === true
+ ? chunkRuntime
+ : filteredRuntime === false
+ ? undefined
+ : filteredRuntime;
+
+ // create a configuration with the root
+ const currentConfiguration = new ConcatConfiguration(
+ currentRoot,
+ activeRuntime
+ );
+
+ // cache failures to add modules
+ const failureCache = new Map();
+
+ // potential optional import candidates
+ /** @type {Set<Module>} */
+ const candidates = new Set();
+
+ // try to add all imports
+ for (const imp of this._getImports(
+ compilation,
+ currentRoot,
+ activeRuntime
+ )) {
+ candidates.add(imp);
+ }
+
+ for (const imp of candidates) {
+ const impCandidates = new Set();
+ const problem = this._tryToAdd(
+ compilation,
+ currentConfiguration,
+ imp,
+ chunkRuntime,
+ activeRuntime,
+ possibleInners,
+ impCandidates,
+ failureCache,
+ chunkGraph,
+ true,
+ stats
+ );
+ if (problem) {
+ failureCache.set(imp, problem);
+ currentConfiguration.addWarning(imp, problem);
+ } else {
+ for (const c of impCandidates) {
+ candidates.add(c);
+ }
+ }
+ }
+ statsCandidates += candidates.size;
+ if (!currentConfiguration.isEmpty()) {
+ const modules = currentConfiguration.getModules();
+ statsSizeSum += modules.size;
+ concatConfigurations.push(currentConfiguration);
+ for (const module of modules) {
+ if (module !== currentConfiguration.rootModule) {
+ usedAsInner.add(module);
+ }
+ }
+ } else {
+ statsEmptyConfigurations++;
+ const optimizationBailouts =
+ moduleGraph.getOptimizationBailout(currentRoot);
+ for (const warning of currentConfiguration.getWarningsSorted()) {
+ optimizationBailouts.push(
+ formatBailoutWarning(warning[0], warning[1])
+ );
+ }
+ }
+ }
+ logger.timeEnd("find modules to concatenate");
+ logger.debug(
+ `${
+ concatConfigurations.length
+ } successful concat configurations (avg size: ${
+ statsSizeSum / concatConfigurations.length
+ }), ${statsEmptyConfigurations} bailed out completely`
+ );
+ logger.debug(
+ `${statsCandidates} candidates were considered for adding (${stats.cached} cached failure, ${stats.alreadyInConfig} already in config, ${stats.invalidModule} invalid module, ${stats.incorrectChunks} incorrect chunks, ${stats.incorrectDependency} incorrect dependency, ${stats.incorrectChunksOfImporter} incorrect chunks of importer, ${stats.incorrectModuleDependency} incorrect module dependency, ${stats.incorrectRuntimeCondition} incorrect runtime condition, ${stats.importerFailed} importer failed, ${stats.added} added)`
+ );
+ // HACK: Sort configurations by length and start with the longest one
+ // to get the biggest groups possible. Used modules are marked with usedModules
+ // TODO: Allow to reuse existing configuration while trying to add dependencies.
+ // This would improve performance. O(n^2) -> O(n)
+ logger.time(`sort concat configurations`);
+ concatConfigurations.sort((a, b) => {
+ return b.modules.size - a.modules.size;
+ });
+ logger.timeEnd(`sort concat configurations`);
+ const usedModules = new Set();
+
+ logger.time("create concatenated modules");
+ asyncLib.each(
+ concatConfigurations,
+ (concatConfiguration, callback) => {
+ const rootModule = concatConfiguration.rootModule;
+
+ // Avoid overlapping configurations
+ // TODO: remove this when todo above is fixed
+ if (usedModules.has(rootModule)) return callback();
+ const modules = concatConfiguration.getModules();
+ for (const m of modules) {
+ usedModules.add(m);
+ }
+
+ // Create a new ConcatenatedModule
+ let newModule = ConcatenatedModule.create(
+ rootModule,
+ modules,
+ concatConfiguration.runtime,
+ compiler.root,
+ compilation.outputOptions.hashFunction
+ );
+
+ const build = () => {
+ newModule.build(
+ compiler.options,
+ compilation,
+ null,
+ null,
+ err => {
+ if (err) {
+ if (!err.module) {
+ err.module = newModule;
+ }
+ return callback(err);
+ }
+ integrate();
+ }
+ );
+ };
+
+ const integrate = () => {
+ if (backCompat) {
+ ChunkGraph.setChunkGraphForModule(newModule, chunkGraph);
+ ModuleGraph.setModuleGraphForModule(newModule, moduleGraph);
+ }
+
+ for (const warning of concatConfiguration.getWarningsSorted()) {
+ moduleGraph
+ .getOptimizationBailout(newModule)
+ .push(formatBailoutWarning(warning[0], warning[1]));
+ }
+ moduleGraph.cloneModuleAttributes(rootModule, newModule);
+ for (const m of modules) {
+ // add to builtModules when one of the included modules was built
+ if (compilation.builtModules.has(m)) {
+ compilation.builtModules.add(newModule);
+ }
+ if (m !== rootModule) {
+ // attach external references to the concatenated module too
+ moduleGraph.copyOutgoingModuleConnections(
+ m,
+ newModule,
+ c => {
+ return (
+ c.originModule === m &&
+ !(
+ c.dependency instanceof HarmonyImportDependency &&
+ modules.has(c.module)
+ )
+ );
+ }
+ );
+ // remove module from chunk
+ for (const chunk of chunkGraph.getModuleChunksIterable(
+ rootModule
+ )) {
+ const sourceTypes = chunkGraph.getChunkModuleSourceTypes(
+ chunk,
+ m
+ );
+ if (sourceTypes.size === 1) {
+ chunkGraph.disconnectChunkAndModule(chunk, m);
+ } else {
+ const newSourceTypes = new Set(sourceTypes);
+ newSourceTypes.delete("javascript");
+ chunkGraph.setChunkModuleSourceTypes(
+ chunk,
+ m,
+ newSourceTypes
+ );
+ }
+ }
+ }
+ }
+ compilation.modules.delete(rootModule);
+ ChunkGraph.clearChunkGraphForModule(rootModule);
+ ModuleGraph.clearModuleGraphForModule(rootModule);
+
+ // remove module from chunk
+ chunkGraph.replaceModule(rootModule, newModule);
+ // replace module references with the concatenated module
+ moduleGraph.moveModuleConnections(rootModule, newModule, c => {
+ const otherModule =
+ c.module === rootModule ? c.originModule : c.module;
+ const innerConnection =
+ c.dependency instanceof HarmonyImportDependency &&
+ modules.has(/** @type {Module} */ (otherModule));
+ return !innerConnection;
+ });
+ // add concatenated module to the compilation
+ compilation.modules.add(newModule);
+
+ callback();
+ };
+
+ build();
+ },
+ err => {
+ logger.timeEnd("create concatenated modules");
+ process.nextTick(callback.bind(null, err));
+ }
+ );
+ }
+ );
+ });
+ }
+
+ /**
+ * @param {Compilation} compilation the compilation
+ * @param {Module} module the module to be added
+ * @param {RuntimeSpec} runtime the runtime scope
+ * @returns {Set<Module>} the imported modules
+ */
+ _getImports(compilation, module, runtime) {
+ const moduleGraph = compilation.moduleGraph;
+ const set = new Set();
+ for (const dep of module.dependencies) {
+ // Get reference info only for harmony Dependencies
+ if (!(dep instanceof HarmonyImportDependency)) continue;
+
+ const connection = moduleGraph.getConnection(dep);
+ // Reference is valid and has a module
+ if (
+ !connection ||
+ !connection.module ||
+ !connection.isTargetActive(runtime)
+ ) {
+ continue;
+ }
+
+ const importedNames = compilation.getDependencyReferencedExports(
+ dep,
+ undefined
+ );
+
+ if (
+ importedNames.every(i =>
+ Array.isArray(i) ? i.length > 0 : i.name.length > 0
+ ) ||
+ Array.isArray(moduleGraph.getProvidedExports(module))
+ ) {
+ set.add(connection.module);
+ }
+ }
+ return set;
+ }
+
+ /**
+ * @param {Compilation} compilation webpack compilation
+ * @param {ConcatConfiguration} config concat configuration (will be modified when added)
+ * @param {Module} module the module to be added
+ * @param {RuntimeSpec} runtime the runtime scope of the generated code
+ * @param {RuntimeSpec} activeRuntime the runtime scope of the root module
+ * @param {Set<Module>} possibleModules modules that are candidates
+ * @param {Set<Module>} candidates list of potential candidates (will be added to)
+ * @param {Map<Module, Module | function(RequestShortener): string>} failureCache cache for problematic modules to be more performant
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @param {boolean} avoidMutateOnFailure avoid mutating the config when adding fails
+ * @param {Statistics} statistics gathering metrics
+ * @returns {null | Module | function(RequestShortener): string} the problematic module
+ */
+ _tryToAdd(
+ compilation,
+ config,
+ module,
+ runtime,
+ activeRuntime,
+ possibleModules,
+ candidates,
+ failureCache,
+ chunkGraph,
+ avoidMutateOnFailure,
+ statistics
+ ) {
+ const cacheEntry = failureCache.get(module);
+ if (cacheEntry) {
+ statistics.cached++;
+ return cacheEntry;
+ }
+
+ // Already added?
+ if (config.has(module)) {
+ statistics.alreadyInConfig++;
+ return null;
+ }
+
+ // Not possible to add?
+ if (!possibleModules.has(module)) {
+ statistics.invalidModule++;
+ failureCache.set(module, module); // cache failures for performance
+ return module;
+ }
+
+ // Module must be in the correct chunks
+ const missingChunks = Array.from(
+ chunkGraph.getModuleChunksIterable(config.rootModule)
+ ).filter(chunk => !chunkGraph.isModuleInChunk(module, chunk));
+ if (missingChunks.length > 0) {
+ /**
+ * @param {RequestShortener} requestShortener request shortener
+ * @returns {string} problem description
+ */
+ const problem = requestShortener => {
+ const missingChunksList = Array.from(
+ new Set(missingChunks.map(chunk => chunk.name || "unnamed chunk(s)"))
+ ).sort();
+ const chunks = Array.from(
+ new Set(
+ Array.from(chunkGraph.getModuleChunksIterable(module)).map(
+ chunk => chunk.name || "unnamed chunk(s)"
+ )
+ )
+ ).sort();
+ return `Module ${module.readableIdentifier(
+ requestShortener
+ )} is not in the same chunk(s) (expected in chunk(s) ${missingChunksList.join(
+ ", "
+ )}, module is in chunk(s) ${chunks.join(", ")})`;
+ };
+ statistics.incorrectChunks++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+
+ const moduleGraph = compilation.moduleGraph;
+
+ const incomingConnections =
+ moduleGraph.getIncomingConnectionsByOriginModule(module);
+
+ const incomingConnectionsFromNonModules =
+ incomingConnections.get(null) || incomingConnections.get(undefined);
+ if (incomingConnectionsFromNonModules) {
+ const activeNonModulesConnections =
+ incomingConnectionsFromNonModules.filter(connection => {
+ // We are not interested in inactive connections
+ // or connections without dependency
+ return connection.isActive(runtime);
+ });
+ if (activeNonModulesConnections.length > 0) {
+ /**
+ * @param {RequestShortener} requestShortener request shortener
+ * @returns {string} problem description
+ */
+ const problem = requestShortener => {
+ const importingExplanations = new Set(
+ activeNonModulesConnections.map(c => c.explanation).filter(Boolean)
+ );
+ const explanations = Array.from(importingExplanations).sort();
+ return `Module ${module.readableIdentifier(
+ requestShortener
+ )} is referenced ${
+ explanations.length > 0
+ ? `by: ${explanations.join(", ")}`
+ : "in an unsupported way"
+ }`;
+ };
+ statistics.incorrectDependency++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+ }
+
+ /** @type {Map<Module, readonly ModuleGraph.ModuleGraphConnection[]>} */
+ const incomingConnectionsFromModules = new Map();
+ for (const [originModule, connections] of incomingConnections) {
+ if (originModule) {
+ // Ignore connection from orphan modules
+ if (chunkGraph.getNumberOfModuleChunks(originModule) === 0) continue;
+
+ // We don't care for connections from other runtimes
+ let originRuntime = undefined;
+ for (const r of chunkGraph.getModuleRuntimes(originModule)) {
+ originRuntime = mergeRuntimeOwned(originRuntime, r);
+ }
+
+ if (!intersectRuntime(runtime, originRuntime)) continue;
+
+ // We are not interested in inactive connections
+ const activeConnections = connections.filter(connection =>
+ connection.isActive(runtime)
+ );
+ if (activeConnections.length > 0)
+ incomingConnectionsFromModules.set(originModule, activeConnections);
+ }
+ }
+
+ const incomingModules = Array.from(incomingConnectionsFromModules.keys());
+
+ // Module must be in the same chunks like the referencing module
+ const otherChunkModules = incomingModules.filter(originModule => {
+ for (const chunk of chunkGraph.getModuleChunksIterable(
+ config.rootModule
+ )) {
+ if (!chunkGraph.isModuleInChunk(originModule, chunk)) {
+ return true;
+ }
+ }
+ return false;
+ });
+ if (otherChunkModules.length > 0) {
+ /**
+ * @param {RequestShortener} requestShortener request shortener
+ * @returns {string} problem description
+ */
+ const problem = requestShortener => {
+ const names = otherChunkModules
+ .map(m => m.readableIdentifier(requestShortener))
+ .sort();
+ return `Module ${module.readableIdentifier(
+ requestShortener
+ )} is referenced from different chunks by these modules: ${names.join(
+ ", "
+ )}`;
+ };
+ statistics.incorrectChunksOfImporter++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+
+ /** @type {Map<Module, readonly ModuleGraph.ModuleGraphConnection[]>} */
+ const nonHarmonyConnections = new Map();
+ for (const [originModule, connections] of incomingConnectionsFromModules) {
+ const selected = connections.filter(
+ connection =>
+ !connection.dependency ||
+ !(connection.dependency instanceof HarmonyImportDependency)
+ );
+ if (selected.length > 0)
+ nonHarmonyConnections.set(originModule, connections);
+ }
+ if (nonHarmonyConnections.size > 0) {
+ /**
+ * @param {RequestShortener} requestShortener request shortener
+ * @returns {string} problem description
+ */
+ const problem = requestShortener => {
+ const names = Array.from(nonHarmonyConnections)
+ .map(([originModule, connections]) => {
+ return `${originModule.readableIdentifier(
+ requestShortener
+ )} (referenced with ${Array.from(
+ new Set(
+ connections
+ .map(c => c.dependency && c.dependency.type)
+ .filter(Boolean)
+ )
+ )
+ .sort()
+ .join(", ")})`;
+ })
+ .sort();
+ return `Module ${module.readableIdentifier(
+ requestShortener
+ )} is referenced from these modules with unsupported syntax: ${names.join(
+ ", "
+ )}`;
+ };
+ statistics.incorrectModuleDependency++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+
+ if (runtime !== undefined && typeof runtime !== "string") {
+ // Module must be consistently referenced in the same runtimes
+ /** @type {{ originModule: Module, runtimeCondition: RuntimeSpec }[]} */
+ const otherRuntimeConnections = [];
+ outer: for (const [
+ originModule,
+ connections
+ ] of incomingConnectionsFromModules) {
+ /** @type {false | RuntimeSpec} */
+ let currentRuntimeCondition = false;
+ for (const connection of connections) {
+ const runtimeCondition = filterRuntime(runtime, runtime => {
+ return connection.isTargetActive(runtime);
+ });
+ if (runtimeCondition === false) continue;
+ if (runtimeCondition === true) continue outer;
+ if (currentRuntimeCondition !== false) {
+ currentRuntimeCondition = mergeRuntime(
+ currentRuntimeCondition,
+ runtimeCondition
+ );
+ } else {
+ currentRuntimeCondition = runtimeCondition;
+ }
+ }
+ if (currentRuntimeCondition !== false) {
+ otherRuntimeConnections.push({
+ originModule,
+ runtimeCondition: currentRuntimeCondition
+ });
+ }
+ }
+ if (otherRuntimeConnections.length > 0) {
+ /**
+ * @param {RequestShortener} requestShortener request shortener
+ * @returns {string} problem description
+ */
+ const problem = requestShortener => {
+ return `Module ${module.readableIdentifier(
+ requestShortener
+ )} is runtime-dependent referenced by these modules: ${Array.from(
+ otherRuntimeConnections,
+ ({ originModule, runtimeCondition }) =>
+ `${originModule.readableIdentifier(
+ requestShortener
+ )} (expected runtime ${runtimeToString(
+ runtime
+ )}, module is only referenced in ${runtimeToString(
+ /** @type {RuntimeSpec} */ (runtimeCondition)
+ )})`
+ ).join(", ")}`;
+ };
+ statistics.incorrectRuntimeCondition++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+ }
+
+ let backup;
+ if (avoidMutateOnFailure) {
+ backup = config.snapshot();
+ }
+
+ // Add the module
+ config.add(module);
+
+ incomingModules.sort(compareModulesByIdentifier);
+
+ // Every module which depends on the added module must be in the configuration too.
+ for (const originModule of incomingModules) {
+ const problem = this._tryToAdd(
+ compilation,
+ config,
+ originModule,
+ runtime,
+ activeRuntime,
+ possibleModules,
+ candidates,
+ failureCache,
+ chunkGraph,
+ false,
+ statistics
+ );
+ if (problem) {
+ if (backup !== undefined) config.rollback(backup);
+ statistics.importerFailed++;
+ failureCache.set(module, problem); // cache failures for performance
+ return problem;
+ }
+ }
+
+ // Add imports to possible candidates list
+ for (const imp of this._getImports(compilation, module, runtime)) {
+ candidates.add(imp);
+ }
+ statistics.added++;
+ return null;
+ }
+}
+
+class ConcatConfiguration {
+ /**
+ * @param {Module} rootModule the root module
+ * @param {RuntimeSpec} runtime the runtime
+ */
+ constructor(rootModule, runtime) {
+ this.rootModule = rootModule;
+ this.runtime = runtime;
+ /** @type {Set<Module>} */
+ this.modules = new Set();
+ this.modules.add(rootModule);
+ /** @type {Map<Module, Module | function(RequestShortener): string>} */
+ this.warnings = new Map();
+ }
+
+ /**
+ * @param {Module} module the module
+ */
+ add(module) {
+ this.modules.add(module);
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {boolean} true, when the module is in the module set
+ */
+ has(module) {
+ return this.modules.has(module);
+ }
+
+ isEmpty() {
+ return this.modules.size === 1;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {Module | function(RequestShortener): string} problem the problem
+ */
+ addWarning(module, problem) {
+ this.warnings.set(module, problem);
+ }
+
+ /**
+ * @returns {Map<Module, Module | function(RequestShortener): string>} warnings
+ */
+ getWarningsSorted() {
+ return new Map(
+ Array.from(this.warnings).sort((a, b) => {
+ const ai = a[0].identifier();
+ const bi = b[0].identifier();
+ if (ai < bi) return -1;
+ if (ai > bi) return 1;
+ return 0;
+ })
+ );
+ }
+
+ /**
+ * @returns {Set<Module>} modules as set
+ */
+ getModules() {
+ return this.modules;
+ }
+
+ snapshot() {
+ return this.modules.size;
+ }
+
+ rollback(snapshot) {
+ const modules = this.modules;
+ for (const m of modules) {
+ if (snapshot === 0) {
+ modules.delete(m);
+ } else {
+ snapshot--;
+ }
+ }
+ }
+}
+
+module.exports = ModuleConcatenationPlugin;
diff --git a/node_modules/webpack/lib/optimize/RealContentHashPlugin.js b/node_modules/webpack/lib/optimize/RealContentHashPlugin.js
new file mode 100644
index 00000000..8a50b5e1
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/RealContentHashPlugin.js
@@ -0,0 +1,467 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { SyncBailHook } = require("tapable");
+const { RawSource, CachedSource, CompatSource } = require("webpack-sources");
+const Compilation = require("../Compilation");
+const WebpackError = require("../WebpackError");
+const { compareSelect, compareStrings } = require("../util/comparators");
+const createHash = require("../util/createHash");
+
+/** @typedef {import("webpack-sources").Source} Source */
+/** @typedef {import("../Cache").Etag} Etag */
+/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {typeof import("../util/Hash")} Hash */
+
+const EMPTY_SET = new Set();
+
+/**
+ * @template T
+ * @param {T | T[]} itemOrItems item or items
+ * @param {Set<T>} list list
+ */
+const addToList = (itemOrItems, list) => {
+ if (Array.isArray(itemOrItems)) {
+ for (const item of itemOrItems) {
+ list.add(item);
+ }
+ } else if (itemOrItems) {
+ list.add(itemOrItems);
+ }
+};
+
+/**
+ * @template T
+ * @param {T[]} input list
+ * @param {function(T): Buffer} fn map function
+ * @returns {Buffer[]} buffers without duplicates
+ */
+const mapAndDeduplicateBuffers = (input, fn) => {
+ // Buffer.equals compares size first so this should be efficient enough
+ // If it becomes a performance problem we can use a map and group by size
+ // instead of looping over all assets.
+ const result = [];
+ outer: for (const value of input) {
+ const buf = fn(value);
+ for (const other of result) {
+ if (buf.equals(other)) continue outer;
+ }
+ result.push(buf);
+ }
+ return result;
+};
+
+/**
+ * Escapes regular expression metacharacters
+ * @param {string} str String to quote
+ * @returns {string} Escaped string
+ */
+const quoteMeta = str => {
+ return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
+};
+
+const cachedSourceMap = new WeakMap();
+
+/**
+ * @param {Source} source source
+ * @returns {CachedSource} cached source
+ */
+const toCachedSource = source => {
+ if (source instanceof CachedSource) {
+ return source;
+ }
+ const entry = cachedSourceMap.get(source);
+ if (entry !== undefined) return entry;
+ const newSource = new CachedSource(CompatSource.from(source));
+ cachedSourceMap.set(source, newSource);
+ return newSource;
+};
+
+/** @typedef {Set<string>} OwnHashes */
+/** @typedef {Set<string>} ReferencedHashes */
+/** @typedef {Set<string>} Hashes */
+
+/**
+ * @typedef {Object} AssetInfoForRealContentHash
+ * @property {string} name
+ * @property {AssetInfo} info
+ * @property {Source} source
+ * @property {RawSource | undefined} newSource
+ * @property {RawSource | undefined} newSourceWithoutOwn
+ * @property {string} content
+ * @property {OwnHashes | undefined} ownHashes
+ * @property {Promise<void> | undefined} contentComputePromise
+ * @property {Promise<void> | undefined} contentComputeWithoutOwnPromise
+ * @property {ReferencedHashes | undefined} referencedHashes
+ * @property {Hashes} hashes
+ */
+
+/**
+ * @typedef {Object} CompilationHooks
+ * @property {SyncBailHook<[Buffer[], string], string>} updateHash
+ */
+
+/** @type {WeakMap<Compilation, CompilationHooks>} */
+const compilationHooksMap = new WeakMap();
+
+class RealContentHashPlugin {
+ /**
+ * @param {Compilation} compilation the compilation
+ * @returns {CompilationHooks} the attached 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 = {
+ updateHash: new SyncBailHook(["content", "oldHash"])
+ };
+ compilationHooksMap.set(compilation, hooks);
+ }
+ return hooks;
+ }
+
+ /**
+ * @param {Object} options options object
+ * @param {string | Hash} options.hashFunction the hash function to use
+ * @param {string} options.hashDigest the hash digest to use
+ */
+ constructor({ hashFunction, hashDigest }) {
+ this._hashFunction = hashFunction;
+ this._hashDigest = hashDigest;
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap("RealContentHashPlugin", compilation => {
+ const cacheAnalyse = compilation.getCache(
+ "RealContentHashPlugin|analyse"
+ );
+ const cacheGenerate = compilation.getCache(
+ "RealContentHashPlugin|generate"
+ );
+ const hooks = RealContentHashPlugin.getCompilationHooks(compilation);
+ compilation.hooks.processAssets.tapPromise(
+ {
+ name: "RealContentHashPlugin",
+ stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH
+ },
+ async () => {
+ const assets = compilation.getAssets();
+ /** @type {AssetInfoForRealContentHash[]} */
+ const assetsWithInfo = [];
+ /** @type {Map<string, [AssetInfoForRealContentHash]>} */
+ const hashToAssets = new Map();
+ for (const { source, info, name } of assets) {
+ const cachedSource = toCachedSource(source);
+ const content = /** @type {string} */ (cachedSource.source());
+ /** @type {Hashes} */
+ const hashes = new Set();
+ addToList(info.contenthash, hashes);
+ /** @type {AssetInfoForRealContentHash} */
+ const data = {
+ name,
+ info,
+ source: cachedSource,
+ newSource: undefined,
+ newSourceWithoutOwn: undefined,
+ content,
+ ownHashes: undefined,
+ contentComputePromise: undefined,
+ contentComputeWithoutOwnPromise: undefined,
+ referencedHashes: undefined,
+ hashes
+ };
+ assetsWithInfo.push(data);
+ for (const hash of hashes) {
+ const list = hashToAssets.get(hash);
+ if (list === undefined) {
+ hashToAssets.set(hash, [data]);
+ } else {
+ list.push(data);
+ }
+ }
+ }
+ if (hashToAssets.size === 0) return;
+ const hashRegExp = new RegExp(
+ Array.from(hashToAssets.keys(), quoteMeta).join("|"),
+ "g"
+ );
+ await Promise.all(
+ assetsWithInfo.map(async asset => {
+ const { name, source, content, hashes } = asset;
+ if (Buffer.isBuffer(content)) {
+ asset.referencedHashes = EMPTY_SET;
+ asset.ownHashes = EMPTY_SET;
+ return;
+ }
+ const etag = cacheAnalyse.mergeEtags(
+ cacheAnalyse.getLazyHashedEtag(source),
+ Array.from(hashes).join("|")
+ );
+ [asset.referencedHashes, asset.ownHashes] =
+ await cacheAnalyse.providePromise(name, etag, () => {
+ const referencedHashes = new Set();
+ let ownHashes = new Set();
+ const inContent = content.match(hashRegExp);
+ if (inContent) {
+ for (const hash of inContent) {
+ if (hashes.has(hash)) {
+ ownHashes.add(hash);
+ continue;
+ }
+ referencedHashes.add(hash);
+ }
+ }
+ return [referencedHashes, ownHashes];
+ });
+ })
+ );
+ /**
+ * @param {string} hash the hash
+ * @returns {undefined | ReferencedHashes} the referenced hashes
+ */
+ const getDependencies = hash => {
+ const assets = hashToAssets.get(hash);
+ if (!assets) {
+ const referencingAssets = assetsWithInfo.filter(asset =>
+ /** @type {ReferencedHashes} */ (asset.referencedHashes).has(
+ hash
+ )
+ );
+ const err = new WebpackError(`RealContentHashPlugin
+Some kind of unexpected caching problem occurred.
+An asset was cached with a reference to another asset (${hash}) that's not in the compilation anymore.
+Either the asset was incorrectly cached, or the referenced asset should also be restored from cache.
+Referenced by:
+${referencingAssets
+ .map(a => {
+ const match = new RegExp(`.{0,20}${quoteMeta(hash)}.{0,20}`).exec(
+ a.content
+ );
+ return ` - ${a.name}: ...${match ? match[0] : "???"}...`;
+ })
+ .join("\n")}`);
+ compilation.errors.push(err);
+ return undefined;
+ }
+ const hashes = new Set();
+ for (const { referencedHashes, ownHashes } of assets) {
+ if (!(/** @type {OwnHashes} */ (ownHashes).has(hash))) {
+ for (const hash of /** @type {OwnHashes} */ (ownHashes)) {
+ hashes.add(hash);
+ }
+ }
+ for (const hash of /** @type {ReferencedHashes} */ (
+ referencedHashes
+ )) {
+ hashes.add(hash);
+ }
+ }
+ return hashes;
+ };
+ /**
+ * @param {string} hash the hash
+ * @returns {string} the hash info
+ */
+ const hashInfo = hash => {
+ const assets = hashToAssets.get(hash);
+ return `${hash} (${Array.from(
+ /** @type {AssetInfoForRealContentHash[]} */ (assets),
+ a => a.name
+ )})`;
+ };
+ const hashesInOrder = new Set();
+ for (const hash of hashToAssets.keys()) {
+ /**
+ * @param {string} hash the hash
+ * @param {Set<string>} stack stack of hashes
+ */
+ const add = (hash, stack) => {
+ const deps = getDependencies(hash);
+ if (!deps) return;
+ stack.add(hash);
+ for (const dep of deps) {
+ if (hashesInOrder.has(dep)) continue;
+ if (stack.has(dep)) {
+ throw new Error(
+ `Circular hash dependency ${Array.from(
+ stack,
+ hashInfo
+ ).join(" -> ")} -> ${hashInfo(dep)}`
+ );
+ }
+ add(dep, stack);
+ }
+ hashesInOrder.add(hash);
+ stack.delete(hash);
+ };
+ if (hashesInOrder.has(hash)) continue;
+ add(hash, new Set());
+ }
+ const hashToNewHash = new Map();
+ /**
+ * @param {AssetInfoForRealContentHash} asset asset info
+ * @returns {Etag} etag
+ */
+ const getEtag = asset =>
+ cacheGenerate.mergeEtags(
+ cacheGenerate.getLazyHashedEtag(asset.source),
+ Array.from(
+ /** @type {ReferencedHashes} */ (asset.referencedHashes),
+ hash => hashToNewHash.get(hash)
+ ).join("|")
+ );
+ /**
+ * @param {AssetInfoForRealContentHash} asset asset info
+ * @returns {Promise<void>}
+ */
+ const computeNewContent = asset => {
+ if (asset.contentComputePromise) return asset.contentComputePromise;
+ return (asset.contentComputePromise = (async () => {
+ if (
+ /** @type {OwnHashes} */ (asset.ownHashes).size > 0 ||
+ Array.from(
+ /** @type {ReferencedHashes} */
+ (asset.referencedHashes)
+ ).some(hash => hashToNewHash.get(hash) !== hash)
+ ) {
+ const identifier = asset.name;
+ const etag = getEtag(asset);
+ asset.newSource = await cacheGenerate.providePromise(
+ identifier,
+ etag,
+ () => {
+ const newContent = asset.content.replace(hashRegExp, hash =>
+ hashToNewHash.get(hash)
+ );
+ return new RawSource(newContent);
+ }
+ );
+ }
+ })());
+ };
+ /**
+ * @param {AssetInfoForRealContentHash} asset asset info
+ * @returns {Promise<void>}
+ */
+ const computeNewContentWithoutOwn = asset => {
+ if (asset.contentComputeWithoutOwnPromise)
+ return asset.contentComputeWithoutOwnPromise;
+ return (asset.contentComputeWithoutOwnPromise = (async () => {
+ if (
+ /** @type {OwnHashes} */ (asset.ownHashes).size > 0 ||
+ Array.from(
+ /** @type {ReferencedHashes} */
+ (asset.referencedHashes)
+ ).some(hash => hashToNewHash.get(hash) !== hash)
+ ) {
+ const identifier = asset.name + "|without-own";
+ const etag = getEtag(asset);
+ asset.newSourceWithoutOwn = await cacheGenerate.providePromise(
+ identifier,
+ etag,
+ () => {
+ const newContent = asset.content.replace(
+ hashRegExp,
+ hash => {
+ if (
+ /** @type {OwnHashes} */ (asset.ownHashes).has(hash)
+ ) {
+ return "";
+ }
+ return hashToNewHash.get(hash);
+ }
+ );
+ return new RawSource(newContent);
+ }
+ );
+ }
+ })());
+ };
+ const comparator = compareSelect(a => a.name, compareStrings);
+ for (const oldHash of hashesInOrder) {
+ const assets =
+ /** @type {AssetInfoForRealContentHash[]} */
+ (hashToAssets.get(oldHash));
+ assets.sort(comparator);
+ await Promise.all(
+ assets.map(asset =>
+ /** @type {OwnHashes} */ (asset.ownHashes).has(oldHash)
+ ? computeNewContentWithoutOwn(asset)
+ : computeNewContent(asset)
+ )
+ );
+ const assetsContent = mapAndDeduplicateBuffers(assets, asset => {
+ if (/** @type {OwnHashes} */ (asset.ownHashes).has(oldHash)) {
+ return asset.newSourceWithoutOwn
+ ? asset.newSourceWithoutOwn.buffer()
+ : asset.source.buffer();
+ } else {
+ return asset.newSource
+ ? asset.newSource.buffer()
+ : asset.source.buffer();
+ }
+ });
+ let newHash = hooks.updateHash.call(assetsContent, oldHash);
+ if (!newHash) {
+ const hash = createHash(this._hashFunction);
+ if (compilation.outputOptions.hashSalt) {
+ hash.update(compilation.outputOptions.hashSalt);
+ }
+ for (const content of assetsContent) {
+ hash.update(content);
+ }
+ const digest = hash.digest(this._hashDigest);
+ newHash = /** @type {string} */ (digest.slice(0, oldHash.length));
+ }
+ hashToNewHash.set(oldHash, newHash);
+ }
+ await Promise.all(
+ assetsWithInfo.map(async asset => {
+ await computeNewContent(asset);
+ const newName = asset.name.replace(hashRegExp, hash =>
+ hashToNewHash.get(hash)
+ );
+
+ const infoUpdate = {};
+ const hash = asset.info.contenthash;
+ infoUpdate.contenthash = Array.isArray(hash)
+ ? hash.map(hash => hashToNewHash.get(hash))
+ : hashToNewHash.get(hash);
+
+ if (asset.newSource !== undefined) {
+ compilation.updateAsset(
+ asset.name,
+ asset.newSource,
+ infoUpdate
+ );
+ } else {
+ compilation.updateAsset(asset.name, asset.source, infoUpdate);
+ }
+
+ if (asset.name !== newName) {
+ compilation.renameAsset(asset.name, newName);
+ }
+ })
+ );
+ }
+ );
+ });
+ }
+}
+
+module.exports = RealContentHashPlugin;
diff --git a/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js
new file mode 100644
index 00000000..6dbc2ae6
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js
@@ -0,0 +1,57 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_BASIC, STAGE_ADVANCED } = require("../OptimizationStages");
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../Compiler")} Compiler */
+
+class RemoveEmptyChunksPlugin {
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap("RemoveEmptyChunksPlugin", compilation => {
+ /**
+ * @param {Iterable<Chunk>} chunks the chunks array
+ * @returns {void}
+ */
+ const handler = chunks => {
+ const chunkGraph = compilation.chunkGraph;
+ for (const chunk of chunks) {
+ if (
+ chunkGraph.getNumberOfChunkModules(chunk) === 0 &&
+ !chunk.hasRuntime() &&
+ chunkGraph.getNumberOfEntryModules(chunk) === 0
+ ) {
+ compilation.chunkGraph.disconnectChunk(chunk);
+ compilation.chunks.delete(chunk);
+ }
+ }
+ };
+
+ // TODO do it once
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "RemoveEmptyChunksPlugin",
+ stage: STAGE_BASIC
+ },
+ handler
+ );
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "RemoveEmptyChunksPlugin",
+ stage: STAGE_ADVANCED
+ },
+ handler
+ );
+ });
+ }
+}
+module.exports = RemoveEmptyChunksPlugin;
diff --git a/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js
new file mode 100644
index 00000000..d609ac00
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js
@@ -0,0 +1,127 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { STAGE_BASIC } = require("../OptimizationStages");
+const Queue = require("../util/Queue");
+const { intersect } = require("../util/SetHelpers");
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../ChunkGroup")} ChunkGroup */
+/** @typedef {import("../Compiler")} Compiler */
+
+class RemoveParentModulesPlugin {
+ /**
+ * @param {Compiler} compiler the compiler
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => {
+ /**
+ * @param {Iterable<Chunk>} chunks the chunks
+ * @param {ChunkGroup[]} chunkGroups the chunk groups
+ */
+ const handler = (chunks, chunkGroups) => {
+ const chunkGraph = compilation.chunkGraph;
+ const queue = new Queue();
+ const availableModulesMap = new WeakMap();
+
+ for (const chunkGroup of compilation.entrypoints.values()) {
+ // initialize available modules for chunks without parents
+ availableModulesMap.set(chunkGroup, new Set());
+ for (const child of chunkGroup.childrenIterable) {
+ queue.enqueue(child);
+ }
+ }
+ for (const chunkGroup of compilation.asyncEntrypoints) {
+ // initialize available modules for chunks without parents
+ availableModulesMap.set(chunkGroup, new Set());
+ for (const child of chunkGroup.childrenIterable) {
+ queue.enqueue(child);
+ }
+ }
+
+ while (queue.length > 0) {
+ const chunkGroup = queue.dequeue();
+ let availableModules = availableModulesMap.get(chunkGroup);
+ let changed = false;
+ for (const parent of chunkGroup.parentsIterable) {
+ const availableModulesInParent = availableModulesMap.get(parent);
+ if (availableModulesInParent !== undefined) {
+ // If we know the available modules in parent: process these
+ if (availableModules === undefined) {
+ // if we have not own info yet: create new entry
+ availableModules = new Set(availableModulesInParent);
+ for (const chunk of parent.chunks) {
+ for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
+ availableModules.add(m);
+ }
+ }
+ availableModulesMap.set(chunkGroup, availableModules);
+ changed = true;
+ } else {
+ for (const m of availableModules) {
+ if (
+ !chunkGraph.isModuleInChunkGroup(m, parent) &&
+ !availableModulesInParent.has(m)
+ ) {
+ availableModules.delete(m);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ if (changed) {
+ // if something changed: enqueue our children
+ for (const child of chunkGroup.childrenIterable) {
+ queue.enqueue(child);
+ }
+ }
+ }
+
+ // now we have available modules for every chunk
+ for (const chunk of chunks) {
+ const availableModulesSets = Array.from(
+ chunk.groupsIterable,
+ chunkGroup => availableModulesMap.get(chunkGroup)
+ );
+ if (availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group
+ const availableModules =
+ availableModulesSets.length === 1
+ ? availableModulesSets[0]
+ : intersect(availableModulesSets);
+ const numberOfModules = chunkGraph.getNumberOfChunkModules(chunk);
+ const toRemove = new Set();
+ if (numberOfModules < availableModules.size) {
+ for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
+ if (availableModules.has(m)) {
+ toRemove.add(m);
+ }
+ }
+ } else {
+ for (const m of availableModules) {
+ if (chunkGraph.isModuleInChunk(m, chunk)) {
+ toRemove.add(m);
+ }
+ }
+ }
+ for (const module of toRemove) {
+ chunkGraph.disconnectChunkAndModule(chunk, module);
+ }
+ }
+ };
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "RemoveParentModulesPlugin",
+ stage: STAGE_BASIC
+ },
+ handler
+ );
+ });
+ }
+}
+module.exports = RemoveParentModulesPlugin;
diff --git a/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js b/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js
new file mode 100644
index 00000000..dda6e001
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js
@@ -0,0 +1,52 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+/** @typedef {import("../Compilation").EntryData} EntryData */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Entrypoint")} Entrypoint */
+
+class RuntimeChunkPlugin {
+ constructor(options) {
+ this.options = {
+ /**
+ * @param {Entrypoint} entrypoint entrypoint name
+ * @returns {string} runtime chunk name
+ */
+ name: entrypoint => `runtime~${entrypoint.name}`,
+ ...options
+ };
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => {
+ compilation.hooks.addEntry.tap(
+ "RuntimeChunkPlugin",
+ (_, { name: entryName }) => {
+ if (entryName === undefined) return;
+ const data =
+ /** @type {EntryData} */
+ (compilation.entries.get(entryName));
+ if (data.options.runtime === undefined && !data.options.dependOn) {
+ // Determine runtime chunk name
+ let name = this.options.name;
+ if (typeof name === "function") {
+ name = name({ name: entryName });
+ }
+ data.options.runtime = name;
+ }
+ }
+ );
+ });
+ }
+}
+
+module.exports = RuntimeChunkPlugin;
diff --git a/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js
new file mode 100644
index 00000000..5628ed38
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js
@@ -0,0 +1,346 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const glob2regexp = require("glob-to-regexp");
+const {
+ JAVASCRIPT_MODULE_TYPE_AUTO,
+ JAVASCRIPT_MODULE_TYPE_ESM,
+ JAVASCRIPT_MODULE_TYPE_DYNAMIC
+} = require("../ModuleTypeConstants");
+const { STAGE_DEFAULT } = require("../OptimizationStages");
+const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency");
+const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
+const formatLocation = require("../formatLocation");
+
+/** @typedef {import("estree").ModuleDeclaration} ModuleDeclaration */
+/** @typedef {import("estree").Statement} Statement */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Dependency")} Dependency */
+/** @typedef {import("../Module")} Module */
+/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
+
+/**
+ * @typedef {Object} ExportInModule
+ * @property {Module} module the module
+ * @property {string} exportName the name of the export
+ * @property {boolean} checked if the export is conditional
+ */
+
+/**
+ * @typedef {Object} ReexportInfo
+ * @property {Map<string, ExportInModule[]>} static
+ * @property {Map<Module, Set<string>>} dynamic
+ */
+
+/** @type {WeakMap<any, Map<string, RegExp>>} */
+const globToRegexpCache = new WeakMap();
+
+/**
+ * @param {string} glob the pattern
+ * @param {Map<string, RegExp>} cache the glob to RegExp cache
+ * @returns {RegExp} a regular expression
+ */
+const globToRegexp = (glob, cache) => {
+ const cacheEntry = cache.get(glob);
+ if (cacheEntry !== undefined) return cacheEntry;
+ if (!glob.includes("/")) {
+ glob = `**/${glob}`;
+ }
+ const baseRegexp = glob2regexp(glob, { globstar: true, extended: true });
+ const regexpSource = baseRegexp.source;
+ const regexp = new RegExp("^(\\./)?" + regexpSource.slice(1));
+ cache.set(glob, regexp);
+ return regexp;
+};
+
+const PLUGIN_NAME = "SideEffectsFlagPlugin";
+
+class SideEffectsFlagPlugin {
+ /**
+ * @param {boolean} analyseSource analyse source code for side effects
+ */
+ constructor(analyseSource = true) {
+ this._analyseSource = analyseSource;
+ }
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ let cache = globToRegexpCache.get(compiler.root);
+ if (cache === undefined) {
+ cache = new Map();
+ globToRegexpCache.set(compiler.root, cache);
+ }
+ compiler.hooks.compilation.tap(
+ PLUGIN_NAME,
+ (compilation, { normalModuleFactory }) => {
+ const moduleGraph = compilation.moduleGraph;
+ normalModuleFactory.hooks.module.tap(PLUGIN_NAME, (module, data) => {
+ const resolveData = data.resourceResolveData;
+ if (
+ resolveData &&
+ resolveData.descriptionFileData &&
+ resolveData.relativePath
+ ) {
+ const sideEffects = resolveData.descriptionFileData.sideEffects;
+ if (sideEffects !== undefined) {
+ if (module.factoryMeta === undefined) {
+ module.factoryMeta = {};
+ }
+ const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(
+ resolveData.relativePath,
+ sideEffects,
+ cache
+ );
+ module.factoryMeta.sideEffectFree = !hasSideEffects;
+ }
+ }
+
+ return module;
+ });
+ normalModuleFactory.hooks.module.tap(PLUGIN_NAME, (module, data) => {
+ if (typeof data.settings.sideEffects === "boolean") {
+ if (module.factoryMeta === undefined) {
+ module.factoryMeta = {};
+ }
+ module.factoryMeta.sideEffectFree = !data.settings.sideEffects;
+ }
+ return module;
+ });
+ if (this._analyseSource) {
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @returns {void}
+ */
+ const parserHandler = parser => {
+ /** @type {undefined | Statement | ModuleDeclaration} */
+ let sideEffectsStatement;
+ parser.hooks.program.tap(PLUGIN_NAME, () => {
+ sideEffectsStatement = undefined;
+ });
+ parser.hooks.statement.tap(
+ { name: PLUGIN_NAME, stage: -100 },
+ statement => {
+ if (sideEffectsStatement) return;
+ if (parser.scope.topLevelScope !== true) return;
+ switch (statement.type) {
+ case "ExpressionStatement":
+ if (
+ !parser.isPure(statement.expression, statement.range[0])
+ ) {
+ sideEffectsStatement = statement;
+ }
+ break;
+ case "IfStatement":
+ case "WhileStatement":
+ case "DoWhileStatement":
+ if (!parser.isPure(statement.test, statement.range[0])) {
+ sideEffectsStatement = statement;
+ }
+ // statement hook will be called for child statements too
+ break;
+ case "ForStatement":
+ if (
+ !parser.isPure(statement.init, statement.range[0]) ||
+ !parser.isPure(
+ statement.test,
+ statement.init
+ ? statement.init.range[1]
+ : statement.range[0]
+ ) ||
+ !parser.isPure(
+ statement.update,
+ statement.test
+ ? statement.test.range[1]
+ : statement.init
+ ? statement.init.range[1]
+ : statement.range[0]
+ )
+ ) {
+ sideEffectsStatement = statement;
+ }
+ // statement hook will be called for child statements too
+ break;
+ case "SwitchStatement":
+ if (
+ !parser.isPure(statement.discriminant, statement.range[0])
+ ) {
+ sideEffectsStatement = statement;
+ }
+ // statement hook will be called for child statements too
+ break;
+ case "VariableDeclaration":
+ case "ClassDeclaration":
+ case "FunctionDeclaration":
+ if (!parser.isPure(statement, statement.range[0])) {
+ sideEffectsStatement = statement;
+ }
+ break;
+ case "ExportNamedDeclaration":
+ case "ExportDefaultDeclaration":
+ if (
+ !parser.isPure(statement.declaration, statement.range[0])
+ ) {
+ sideEffectsStatement = statement;
+ }
+ break;
+ case "LabeledStatement":
+ case "BlockStatement":
+ // statement hook will be called for child statements too
+ break;
+ case "EmptyStatement":
+ break;
+ case "ExportAllDeclaration":
+ case "ImportDeclaration":
+ // imports will be handled by the dependencies
+ break;
+ default:
+ sideEffectsStatement = statement;
+ break;
+ }
+ }
+ );
+ parser.hooks.finish.tap(PLUGIN_NAME, () => {
+ if (sideEffectsStatement === undefined) {
+ parser.state.module.buildMeta.sideEffectFree = true;
+ } else {
+ const { loc, type } = sideEffectsStatement;
+ moduleGraph
+ .getOptimizationBailout(parser.state.module)
+ .push(
+ () =>
+ `Statement (${type}) with side effects in source code at ${formatLocation(
+ loc
+ )}`
+ );
+ }
+ });
+ };
+ for (const key of [
+ JAVASCRIPT_MODULE_TYPE_AUTO,
+ JAVASCRIPT_MODULE_TYPE_ESM,
+ JAVASCRIPT_MODULE_TYPE_DYNAMIC
+ ]) {
+ normalModuleFactory.hooks.parser
+ .for(key)
+ .tap(PLUGIN_NAME, parserHandler);
+ }
+ }
+ compilation.hooks.optimizeDependencies.tap(
+ {
+ name: PLUGIN_NAME,
+ stage: STAGE_DEFAULT
+ },
+ modules => {
+ const logger = compilation.getLogger(
+ "webpack.SideEffectsFlagPlugin"
+ );
+
+ logger.time("update dependencies");
+ for (const module of modules) {
+ if (module.getSideEffectsConnectionState(moduleGraph) === false) {
+ const exportsInfo = moduleGraph.getExportsInfo(module);
+ for (const connection of moduleGraph.getIncomingConnections(
+ module
+ )) {
+ const dep = connection.dependency;
+ let isReexport;
+ if (
+ (isReexport =
+ dep instanceof
+ HarmonyExportImportedSpecifierDependency) ||
+ (dep instanceof HarmonyImportSpecifierDependency &&
+ !dep.namespaceObjectAsContext)
+ ) {
+ // TODO improve for export *
+ if (isReexport && dep.name) {
+ const exportInfo = moduleGraph.getExportInfo(
+ /** @type {Module} */ (connection.originModule),
+ dep.name
+ );
+ exportInfo.moveTarget(
+ moduleGraph,
+ ({ module }) =>
+ module.getSideEffectsConnectionState(moduleGraph) ===
+ false,
+ ({ module: newModule, export: exportName }) => {
+ moduleGraph.updateModule(dep, newModule);
+ moduleGraph.addExplanation(
+ dep,
+ "(skipped side-effect-free modules)"
+ );
+ const ids = dep.getIds(moduleGraph);
+ dep.setIds(
+ moduleGraph,
+ exportName
+ ? [...exportName, ...ids.slice(1)]
+ : ids.slice(1)
+ );
+ return moduleGraph.getConnection(dep);
+ }
+ );
+ continue;
+ }
+ // TODO improve for nested imports
+ const ids = dep.getIds(moduleGraph);
+ if (ids.length > 0) {
+ const exportInfo = exportsInfo.getExportInfo(ids[0]);
+ const target = exportInfo.getTarget(
+ moduleGraph,
+ ({ module }) =>
+ module.getSideEffectsConnectionState(moduleGraph) ===
+ false
+ );
+ if (!target) continue;
+
+ moduleGraph.updateModule(dep, target.module);
+ moduleGraph.addExplanation(
+ dep,
+ "(skipped side-effect-free modules)"
+ );
+ dep.setIds(
+ moduleGraph,
+ target.export
+ ? [...target.export, ...ids.slice(1)]
+ : ids.slice(1)
+ );
+ }
+ }
+ }
+ }
+ }
+ logger.timeEnd("update dependencies");
+ }
+ );
+ }
+ );
+ }
+
+ /**
+ * @param {string} moduleName the module name
+ * @param {undefined | boolean | string | string[]} flagValue the flag value
+ * @param {Map<string, RegExp>} cache cache for glob to regexp
+ * @returns {boolean | undefined} true, when the module has side effects, undefined or false when not
+ */
+ static moduleHasSideEffects(moduleName, flagValue, cache) {
+ switch (typeof flagValue) {
+ case "undefined":
+ return true;
+ case "boolean":
+ return flagValue;
+ case "string":
+ return globToRegexp(flagValue, cache).test(moduleName);
+ case "object":
+ return flagValue.some(glob =>
+ SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob, cache)
+ );
+ }
+ }
+}
+module.exports = SideEffectsFlagPlugin;
diff --git a/node_modules/webpack/lib/optimize/SplitChunksPlugin.js b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js
new file mode 100644
index 00000000..2e79ab6a
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js
@@ -0,0 +1,1763 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const Chunk = require("../Chunk");
+const { STAGE_ADVANCED } = require("../OptimizationStages");
+const WebpackError = require("../WebpackError");
+const { requestToId } = require("../ids/IdHelpers");
+const { isSubset } = require("../util/SetHelpers");
+const SortableSet = require("../util/SortableSet");
+const {
+ compareModulesByIdentifier,
+ compareIterables
+} = require("../util/comparators");
+const createHash = require("../util/createHash");
+const deterministicGrouping = require("../util/deterministicGrouping");
+const { makePathsRelative } = require("../util/identifier");
+const memoize = require("../util/memoize");
+const MinMaxSizeWarning = require("./MinMaxSizeWarning");
+
+/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksCacheGroup} OptimizationSplitChunksCacheGroup */
+/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksGetCacheGroups} OptimizationSplitChunksGetCacheGroups */
+/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksOptions} OptimizationSplitChunksOptions */
+/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksSizes} OptimizationSplitChunksSizes */
+/** @typedef {import("../../declarations/WebpackOptions").Output} OutputOptions */
+/** @typedef {import("../ChunkGraph")} ChunkGraph */
+/** @typedef {import("../ChunkGroup")} ChunkGroup */
+/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
+/** @typedef {import("../Compilation").PathData} PathData */
+/** @typedef {import("../Compiler")} Compiler */
+/** @typedef {import("../Module")} Module */
+/** @typedef {import("../ModuleGraph")} ModuleGraph */
+/** @typedef {import("../util/deterministicGrouping").GroupedItems<Module>} DeterministicGroupingGroupedItemsForModule */
+/** @typedef {import("../util/deterministicGrouping").Options<Module>} DeterministicGroupingOptionsForModule */
+
+/** @typedef {Record<string, number>} SplitChunksSizes */
+
+/**
+ * @callback ChunkFilterFunction
+ * @param {Chunk} chunk
+ * @returns {boolean | undefined}
+ */
+
+/**
+ * @callback CombineSizeFunction
+ * @param {number} a
+ * @param {number} b
+ * @returns {number}
+ */
+
+/**
+ * @typedef {Object} CacheGroupSource
+ * @property {string=} key
+ * @property {number=} priority
+ * @property {GetName=} getName
+ * @property {ChunkFilterFunction=} chunksFilter
+ * @property {boolean=} enforce
+ * @property {SplitChunksSizes} minSize
+ * @property {SplitChunksSizes} minSizeReduction
+ * @property {SplitChunksSizes} minRemainingSize
+ * @property {SplitChunksSizes} enforceSizeThreshold
+ * @property {SplitChunksSizes} maxAsyncSize
+ * @property {SplitChunksSizes} maxInitialSize
+ * @property {number=} minChunks
+ * @property {number=} maxAsyncRequests
+ * @property {number=} maxInitialRequests
+ * @property {(string | function(PathData, AssetInfo=): string)=} filename
+ * @property {string=} idHint
+ * @property {string=} automaticNameDelimiter
+ * @property {boolean=} reuseExistingChunk
+ * @property {boolean=} usedExports
+ */
+
+/**
+ * @typedef {Object} CacheGroup
+ * @property {string} key
+ * @property {number=} priority
+ * @property {GetName=} getName
+ * @property {ChunkFilterFunction=} chunksFilter
+ * @property {SplitChunksSizes} minSize
+ * @property {SplitChunksSizes} minSizeReduction
+ * @property {SplitChunksSizes} minRemainingSize
+ * @property {SplitChunksSizes} enforceSizeThreshold
+ * @property {SplitChunksSizes} maxAsyncSize
+ * @property {SplitChunksSizes} maxInitialSize
+ * @property {number=} minChunks
+ * @property {number=} maxAsyncRequests
+ * @property {number=} maxInitialRequests
+ * @property {(string | function(PathData, AssetInfo=): string)=} filename
+ * @property {string=} idHint
+ * @property {string} automaticNameDelimiter
+ * @property {boolean} reuseExistingChunk
+ * @property {boolean} usedExports
+ * @property {boolean} _validateSize
+ * @property {boolean} _validateRemainingSize
+ * @property {SplitChunksSizes} _minSizeForMaxSize
+ * @property {boolean} _conditionalEnforce
+ */
+
+/**
+ * @typedef {Object} FallbackCacheGroup
+ * @property {ChunkFilterFunction} chunksFilter
+ * @property {SplitChunksSizes} minSize
+ * @property {SplitChunksSizes} maxAsyncSize
+ * @property {SplitChunksSizes} maxInitialSize
+ * @property {string} automaticNameDelimiter
+ */
+
+/**
+ * @typedef {Object} CacheGroupsContext
+ * @property {ModuleGraph} moduleGraph
+ * @property {ChunkGraph} chunkGraph
+ */
+
+/**
+ * @callback GetCacheGroups
+ * @param {Module} module
+ * @param {CacheGroupsContext} context
+ * @returns {CacheGroupSource[]}
+ */
+
+/**
+ * @callback GetName
+ * @param {Module=} module
+ * @param {Chunk[]=} chunks
+ * @param {string=} key
+ * @returns {string=}
+ */
+
+/**
+ * @typedef {Object} SplitChunksOptions
+ * @property {ChunkFilterFunction} chunksFilter
+ * @property {string[]} defaultSizeTypes
+ * @property {SplitChunksSizes} minSize
+ * @property {SplitChunksSizes} minSizeReduction
+ * @property {SplitChunksSizes} minRemainingSize
+ * @property {SplitChunksSizes} enforceSizeThreshold
+ * @property {SplitChunksSizes} maxInitialSize
+ * @property {SplitChunksSizes} maxAsyncSize
+ * @property {number} minChunks
+ * @property {number} maxAsyncRequests
+ * @property {number} maxInitialRequests
+ * @property {boolean} hidePathInfo
+ * @property {string | function(PathData, AssetInfo=): string} filename
+ * @property {string} automaticNameDelimiter
+ * @property {GetCacheGroups} getCacheGroups
+ * @property {GetName} getName
+ * @property {boolean} usedExports
+ * @property {FallbackCacheGroup} fallbackCacheGroup
+ */
+
+/**
+ * @typedef {Object} ChunksInfoItem
+ * @property {SortableSet<Module>} modules
+ * @property {CacheGroup} cacheGroup
+ * @property {number} cacheGroupIndex
+ * @property {string} name
+ * @property {Record<string, number>} sizes
+ * @property {Set<Chunk>} chunks
+ * @property {Set<Chunk>} reuseableChunks
+ * @property {Set<bigint | Chunk>} chunksKeys
+ */
+
+const defaultGetName = /** @type {GetName} */ (() => {});
+
+const deterministicGroupingForModules =
+ /** @type {function(DeterministicGroupingOptionsForModule): DeterministicGroupingGroupedItemsForModule[]} */ (
+ deterministicGrouping
+ );
+
+/** @type {WeakMap<Module, string>} */
+const getKeyCache = new WeakMap();
+
+/**
+ * @param {string} name a filename to hash
+ * @param {OutputOptions} outputOptions hash function used
+ * @returns {string} hashed filename
+ */
+const hashFilename = (name, outputOptions) => {
+ const digest = /** @type {string} */ (
+ createHash(outputOptions.hashFunction)
+ .update(name)
+ .digest(outputOptions.hashDigest)
+ );
+ return digest.slice(0, 8);
+};
+
+/**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} the number of requests
+ */
+const getRequests = chunk => {
+ let requests = 0;
+ for (const chunkGroup of chunk.groupsIterable) {
+ requests = Math.max(requests, chunkGroup.chunks.length);
+ }
+ return requests;
+};
+
+const mapObject = (obj, fn) => {
+ const newObj = Object.create(null);
+ for (const key of Object.keys(obj)) {
+ newObj[key] = fn(obj[key], key);
+ }
+ return newObj;
+};
+
+/**
+ * @template T
+ * @param {Set<T>} a set
+ * @param {Set<T>} b other set
+ * @returns {boolean} true if at least one item of a is in b
+ */
+const isOverlap = (a, b) => {
+ for (const item of a) {
+ if (b.has(item)) return true;
+ }
+ return false;
+};
+
+const compareModuleIterables = compareIterables(compareModulesByIdentifier);
+
+/**
+ * @param {ChunksInfoItem} a item
+ * @param {ChunksInfoItem} b item
+ * @returns {number} compare result
+ */
+const compareEntries = (a, b) => {
+ // 1. by priority
+ const diffPriority = a.cacheGroup.priority - b.cacheGroup.priority;
+ if (diffPriority) return diffPriority;
+ // 2. by number of chunks
+ const diffCount = a.chunks.size - b.chunks.size;
+ if (diffCount) return diffCount;
+ // 3. by size reduction
+ const aSizeReduce = totalSize(a.sizes) * (a.chunks.size - 1);
+ const bSizeReduce = totalSize(b.sizes) * (b.chunks.size - 1);
+ const diffSizeReduce = aSizeReduce - bSizeReduce;
+ if (diffSizeReduce) return diffSizeReduce;
+ // 4. by cache group index
+ const indexDiff = b.cacheGroupIndex - a.cacheGroupIndex;
+ if (indexDiff) return indexDiff;
+ // 5. by number of modules (to be able to compare by identifier)
+ const modulesA = a.modules;
+ const modulesB = b.modules;
+ const diff = modulesA.size - modulesB.size;
+ if (diff) return diff;
+ // 6. by module identifiers
+ modulesA.sort();
+ modulesB.sort();
+ return compareModuleIterables(modulesA, modulesB);
+};
+
+/**
+ * @param {Chunk} chunk the chunk
+ * @returns {boolean} true, if the chunk is an entry chunk
+ */
+const INITIAL_CHUNK_FILTER = chunk => chunk.canBeInitial();
+/**
+ * @param {Chunk} chunk the chunk
+ * @returns {boolean} true, if the chunk is an async chunk
+ */
+const ASYNC_CHUNK_FILTER = chunk => !chunk.canBeInitial();
+/**
+ * @param {Chunk} chunk the chunk
+ * @returns {boolean} always true
+ */
+const ALL_CHUNK_FILTER = chunk => true;
+
+/**
+ * @param {OptimizationSplitChunksSizes | undefined} value the sizes
+ * @param {string[]} defaultSizeTypes the default size types
+ * @returns {SplitChunksSizes} normalized representation
+ */
+const normalizeSizes = (value, defaultSizeTypes) => {
+ if (typeof value === "number") {
+ /** @type {Record<string, number>} */
+ const o = {};
+ for (const sizeType of defaultSizeTypes) o[sizeType] = value;
+ return o;
+ } else if (typeof value === "object" && value !== null) {
+ return { ...value };
+ } else {
+ return {};
+ }
+};
+
+/**
+ * @param {...SplitChunksSizes} sizes the sizes
+ * @returns {SplitChunksSizes} the merged sizes
+ */
+const mergeSizes = (...sizes) => {
+ /** @type {SplitChunksSizes} */
+ let merged = {};
+ for (let i = sizes.length - 1; i >= 0; i--) {
+ merged = Object.assign(merged, sizes[i]);
+ }
+ return merged;
+};
+
+/**
+ * @param {SplitChunksSizes} sizes the sizes
+ * @returns {boolean} true, if there are sizes > 0
+ */
+const hasNonZeroSizes = sizes => {
+ for (const key of Object.keys(sizes)) {
+ if (sizes[key] > 0) return true;
+ }
+ return false;
+};
+
+/**
+ * @param {SplitChunksSizes} a first sizes
+ * @param {SplitChunksSizes} b second sizes
+ * @param {CombineSizeFunction} combine a function to combine sizes
+ * @returns {SplitChunksSizes} the combine sizes
+ */
+const combineSizes = (a, b, combine) => {
+ const aKeys = new Set(Object.keys(a));
+ const bKeys = new Set(Object.keys(b));
+ /** @type {SplitChunksSizes} */
+ const result = {};
+ for (const key of aKeys) {
+ if (bKeys.has(key)) {
+ result[key] = combine(a[key], b[key]);
+ } else {
+ result[key] = a[key];
+ }
+ }
+ for (const key of bKeys) {
+ if (!aKeys.has(key)) {
+ result[key] = b[key];
+ }
+ }
+ return result;
+};
+
+/**
+ * @param {SplitChunksSizes} sizes the sizes
+ * @param {SplitChunksSizes} minSize the min sizes
+ * @returns {boolean} true if there are sizes and all existing sizes are at least `minSize`
+ */
+const checkMinSize = (sizes, minSize) => {
+ for (const key of Object.keys(minSize)) {
+ const size = sizes[key];
+ if (size === undefined || size === 0) continue;
+ if (size < minSize[key]) return false;
+ }
+ return true;
+};
+
+/**
+ * @param {SplitChunksSizes} sizes the sizes
+ * @param {SplitChunksSizes} minSizeReduction the min sizes
+ * @param {number} chunkCount number of chunks
+ * @returns {boolean} true if there are sizes and all existing sizes are at least `minSizeReduction`
+ */
+const checkMinSizeReduction = (sizes, minSizeReduction, chunkCount) => {
+ for (const key of Object.keys(minSizeReduction)) {
+ const size = sizes[key];
+ if (size === undefined || size === 0) continue;
+ if (size * chunkCount < minSizeReduction[key]) return false;
+ }
+ return true;
+};
+
+/**
+ * @param {SplitChunksSizes} sizes the sizes
+ * @param {SplitChunksSizes} minSize the min sizes
+ * @returns {undefined | string[]} list of size types that are below min size
+ */
+const getViolatingMinSizes = (sizes, minSize) => {
+ let list;
+ for (const key of Object.keys(minSize)) {
+ const size = sizes[key];
+ if (size === undefined || size === 0) continue;
+ if (size < minSize[key]) {
+ if (list === undefined) list = [key];
+ else list.push(key);
+ }
+ }
+ return list;
+};
+
+/**
+ * @param {SplitChunksSizes} sizes the sizes
+ * @returns {number} the total size
+ */
+const totalSize = sizes => {
+ let size = 0;
+ for (const key of Object.keys(sizes)) {
+ size += sizes[key];
+ }
+ return size;
+};
+
+/**
+ * @param {false|string|Function|undefined} name the chunk name
+ * @returns {GetName | undefined} a function to get the name of the chunk
+ */
+const normalizeName = name => {
+ if (typeof name === "string") {
+ return () => name;
+ }
+ if (typeof name === "function") {
+ return /** @type {GetName} */ (name);
+ }
+};
+
+/**
+ * @param {OptimizationSplitChunksCacheGroup["chunks"]} chunks the chunk filter option
+ * @returns {ChunkFilterFunction} the chunk filter function
+ */
+const normalizeChunksFilter = chunks => {
+ if (chunks === "initial") {
+ return INITIAL_CHUNK_FILTER;
+ }
+ if (chunks === "async") {
+ return ASYNC_CHUNK_FILTER;
+ }
+ if (chunks === "all") {
+ return ALL_CHUNK_FILTER;
+ }
+ if (chunks instanceof RegExp) {
+ return chunk => {
+ return chunk.name ? chunks.test(chunk.name) : false;
+ };
+ }
+ if (typeof chunks === "function") {
+ return chunks;
+ }
+};
+
+/**
+ * @param {GetCacheGroups | Record<string, false|string|RegExp|OptimizationSplitChunksGetCacheGroups|OptimizationSplitChunksCacheGroup>} cacheGroups the cache group options
+ * @param {string[]} defaultSizeTypes the default size types
+ * @returns {GetCacheGroups} a function to get the cache groups
+ */
+const normalizeCacheGroups = (cacheGroups, defaultSizeTypes) => {
+ if (typeof cacheGroups === "function") {
+ return cacheGroups;
+ }
+ if (typeof cacheGroups === "object" && cacheGroups !== null) {
+ /** @type {(function(Module, CacheGroupsContext, CacheGroupSource[]): void)[]} */
+ const handlers = [];
+ for (const key of Object.keys(cacheGroups)) {
+ const option = cacheGroups[key];
+ if (option === false) {
+ continue;
+ }
+ if (typeof option === "string" || option instanceof RegExp) {
+ const source = createCacheGroupSource({}, key, defaultSizeTypes);
+ handlers.push((module, context, results) => {
+ if (checkTest(option, module, context)) {
+ results.push(source);
+ }
+ });
+ } else if (typeof option === "function") {
+ const cache = new WeakMap();
+ handlers.push((module, context, results) => {
+ const result = option(module);
+ if (result) {
+ const groups = Array.isArray(result) ? result : [result];
+ for (const group of groups) {
+ const cachedSource = cache.get(group);
+ if (cachedSource !== undefined) {
+ results.push(cachedSource);
+ } else {
+ const source = createCacheGroupSource(
+ group,
+ key,
+ defaultSizeTypes
+ );
+ cache.set(group, source);
+ results.push(source);
+ }
+ }
+ }
+ });
+ } else {
+ const source = createCacheGroupSource(option, key, defaultSizeTypes);
+ handlers.push((module, context, results) => {
+ if (
+ checkTest(option.test, module, context) &&
+ checkModuleType(option.type, module) &&
+ checkModuleLayer(option.layer, module)
+ ) {
+ results.push(source);
+ }
+ });
+ }
+ }
+ /**
+ * @param {Module} module the current module
+ * @param {CacheGroupsContext} context the current context
+ * @returns {CacheGroupSource[]} the matching cache groups
+ */
+ const fn = (module, context) => {
+ /** @type {CacheGroupSource[]} */
+ let results = [];
+ for (const fn of handlers) {
+ fn(module, context, results);
+ }
+ return results;
+ };
+ return fn;
+ }
+ return () => null;
+};
+
+/**
+ * @param {undefined|boolean|string|RegExp|Function} test test option
+ * @param {Module} module the module
+ * @param {CacheGroupsContext} context context object
+ * @returns {boolean} true, if the module should be selected
+ */
+const checkTest = (test, module, context) => {
+ if (test === undefined) return true;
+ if (typeof test === "function") {
+ return test(module, context);
+ }
+ if (typeof test === "boolean") return test;
+ if (typeof test === "string") {
+ const name = module.nameForCondition();
+ return name && name.startsWith(test);
+ }
+ if (test instanceof RegExp) {
+ const name = module.nameForCondition();
+ return name && test.test(name);
+ }
+ return false;
+};
+
+/**
+ * @param {undefined|string|RegExp|Function} test type option
+ * @param {Module} module the module
+ * @returns {boolean} true, if the module should be selected
+ */
+const checkModuleType = (test, module) => {
+ if (test === undefined) return true;
+ if (typeof test === "function") {
+ return test(module.type);
+ }
+ if (typeof test === "string") {
+ const type = module.type;
+ return test === type;
+ }
+ if (test instanceof RegExp) {
+ const type = module.type;
+ return test.test(type);
+ }
+ return false;
+};
+
+/**
+ * @param {undefined|string|RegExp|Function} test type option
+ * @param {Module} module the module
+ * @returns {boolean} true, if the module should be selected
+ */
+const checkModuleLayer = (test, module) => {
+ if (test === undefined) return true;
+ if (typeof test === "function") {
+ return test(module.layer);
+ }
+ if (typeof test === "string") {
+ const layer = module.layer;
+ return test === "" ? !layer : layer && layer.startsWith(test);
+ }
+ if (test instanceof RegExp) {
+ const layer = module.layer;
+ return test.test(layer);
+ }
+ return false;
+};
+
+/**
+ * @param {OptimizationSplitChunksCacheGroup} options the group options
+ * @param {string} key key of cache group
+ * @param {string[]} defaultSizeTypes the default size types
+ * @returns {CacheGroupSource} the normalized cached group
+ */
+const createCacheGroupSource = (options, key, defaultSizeTypes) => {
+ const minSize = normalizeSizes(options.minSize, defaultSizeTypes);
+ const minSizeReduction = normalizeSizes(
+ options.minSizeReduction,
+ defaultSizeTypes
+ );
+ const maxSize = normalizeSizes(options.maxSize, defaultSizeTypes);
+ return {
+ key,
+ priority: options.priority,
+ getName: normalizeName(options.name),
+ chunksFilter: normalizeChunksFilter(options.chunks),
+ enforce: options.enforce,
+ minSize,
+ minSizeReduction,
+ minRemainingSize: mergeSizes(
+ normalizeSizes(options.minRemainingSize, defaultSizeTypes),
+ minSize
+ ),
+ enforceSizeThreshold: normalizeSizes(
+ options.enforceSizeThreshold,
+ defaultSizeTypes
+ ),
+ maxAsyncSize: mergeSizes(
+ normalizeSizes(options.maxAsyncSize, defaultSizeTypes),
+ maxSize
+ ),
+ maxInitialSize: mergeSizes(
+ normalizeSizes(options.maxInitialSize, defaultSizeTypes),
+ maxSize
+ ),
+ minChunks: options.minChunks,
+ maxAsyncRequests: options.maxAsyncRequests,
+ maxInitialRequests: options.maxInitialRequests,
+ filename: options.filename,
+ idHint: options.idHint,
+ automaticNameDelimiter: options.automaticNameDelimiter,
+ reuseExistingChunk: options.reuseExistingChunk,
+ usedExports: options.usedExports
+ };
+};
+
+module.exports = class SplitChunksPlugin {
+ /**
+ * @param {OptimizationSplitChunksOptions=} options plugin options
+ */
+ constructor(options = {}) {
+ const defaultSizeTypes = options.defaultSizeTypes || [
+ "javascript",
+ "unknown"
+ ];
+ const fallbackCacheGroup = options.fallbackCacheGroup || {};
+ const minSize = normalizeSizes(options.minSize, defaultSizeTypes);
+ const minSizeReduction = normalizeSizes(
+ options.minSizeReduction,
+ defaultSizeTypes
+ );
+ const maxSize = normalizeSizes(options.maxSize, defaultSizeTypes);
+
+ /** @type {SplitChunksOptions} */
+ this.options = {
+ chunksFilter: normalizeChunksFilter(options.chunks || "all"),
+ defaultSizeTypes,
+ minSize,
+ minSizeReduction,
+ minRemainingSize: mergeSizes(
+ normalizeSizes(options.minRemainingSize, defaultSizeTypes),
+ minSize
+ ),
+ enforceSizeThreshold: normalizeSizes(
+ options.enforceSizeThreshold,
+ defaultSizeTypes
+ ),
+ maxAsyncSize: mergeSizes(
+ normalizeSizes(options.maxAsyncSize, defaultSizeTypes),
+ maxSize
+ ),
+ maxInitialSize: mergeSizes(
+ normalizeSizes(options.maxInitialSize, defaultSizeTypes),
+ maxSize
+ ),
+ minChunks: options.minChunks || 1,
+ maxAsyncRequests: options.maxAsyncRequests || 1,
+ maxInitialRequests: options.maxInitialRequests || 1,
+ hidePathInfo: options.hidePathInfo || false,
+ filename: options.filename || undefined,
+ getCacheGroups: normalizeCacheGroups(
+ options.cacheGroups,
+ defaultSizeTypes
+ ),
+ getName: options.name ? normalizeName(options.name) : defaultGetName,
+ automaticNameDelimiter: options.automaticNameDelimiter,
+ usedExports: options.usedExports,
+ fallbackCacheGroup: {
+ chunksFilter: normalizeChunksFilter(
+ fallbackCacheGroup.chunks || options.chunks || "all"
+ ),
+ minSize: mergeSizes(
+ normalizeSizes(fallbackCacheGroup.minSize, defaultSizeTypes),
+ minSize
+ ),
+ maxAsyncSize: mergeSizes(
+ normalizeSizes(fallbackCacheGroup.maxAsyncSize, defaultSizeTypes),
+ normalizeSizes(fallbackCacheGroup.maxSize, defaultSizeTypes),
+ normalizeSizes(options.maxAsyncSize, defaultSizeTypes),
+ normalizeSizes(options.maxSize, defaultSizeTypes)
+ ),
+ maxInitialSize: mergeSizes(
+ normalizeSizes(fallbackCacheGroup.maxInitialSize, defaultSizeTypes),
+ normalizeSizes(fallbackCacheGroup.maxSize, defaultSizeTypes),
+ normalizeSizes(options.maxInitialSize, defaultSizeTypes),
+ normalizeSizes(options.maxSize, defaultSizeTypes)
+ ),
+ automaticNameDelimiter:
+ fallbackCacheGroup.automaticNameDelimiter ||
+ options.automaticNameDelimiter ||
+ "~"
+ }
+ };
+
+ /** @type {WeakMap<CacheGroupSource, CacheGroup>} */
+ this._cacheGroupCache = new WeakMap();
+ }
+
+ /**
+ * @param {CacheGroupSource} cacheGroupSource source
+ * @returns {CacheGroup} the cache group (cached)
+ */
+ _getCacheGroup(cacheGroupSource) {
+ const cacheEntry = this._cacheGroupCache.get(cacheGroupSource);
+ if (cacheEntry !== undefined) return cacheEntry;
+ const minSize = mergeSizes(
+ cacheGroupSource.minSize,
+ cacheGroupSource.enforce ? undefined : this.options.minSize
+ );
+ const minSizeReduction = mergeSizes(
+ cacheGroupSource.minSizeReduction,
+ cacheGroupSource.enforce ? undefined : this.options.minSizeReduction
+ );
+ const minRemainingSize = mergeSizes(
+ cacheGroupSource.minRemainingSize,
+ cacheGroupSource.enforce ? undefined : this.options.minRemainingSize
+ );
+ const enforceSizeThreshold = mergeSizes(
+ cacheGroupSource.enforceSizeThreshold,
+ cacheGroupSource.enforce ? undefined : this.options.enforceSizeThreshold
+ );
+ const cacheGroup = {
+ key: cacheGroupSource.key,
+ priority: cacheGroupSource.priority || 0,
+ chunksFilter: cacheGroupSource.chunksFilter || this.options.chunksFilter,
+ minSize,
+ minSizeReduction,
+ minRemainingSize,
+ enforceSizeThreshold,
+ maxAsyncSize: mergeSizes(
+ cacheGroupSource.maxAsyncSize,
+ cacheGroupSource.enforce ? undefined : this.options.maxAsyncSize
+ ),
+ maxInitialSize: mergeSizes(
+ cacheGroupSource.maxInitialSize,
+ cacheGroupSource.enforce ? undefined : this.options.maxInitialSize
+ ),
+ minChunks:
+ cacheGroupSource.minChunks !== undefined
+ ? cacheGroupSource.minChunks
+ : cacheGroupSource.enforce
+ ? 1
+ : this.options.minChunks,
+ maxAsyncRequests:
+ cacheGroupSource.maxAsyncRequests !== undefined
+ ? cacheGroupSource.maxAsyncRequests
+ : cacheGroupSource.enforce
+ ? Infinity
+ : this.options.maxAsyncRequests,
+ maxInitialRequests:
+ cacheGroupSource.maxInitialRequests !== undefined
+ ? cacheGroupSource.maxInitialRequests
+ : cacheGroupSource.enforce
+ ? Infinity
+ : this.options.maxInitialRequests,
+ getName:
+ cacheGroupSource.getName !== undefined
+ ? cacheGroupSource.getName
+ : this.options.getName,
+ usedExports:
+ cacheGroupSource.usedExports !== undefined
+ ? cacheGroupSource.usedExports
+ : this.options.usedExports,
+ filename:
+ cacheGroupSource.filename !== undefined
+ ? cacheGroupSource.filename
+ : this.options.filename,
+ automaticNameDelimiter:
+ cacheGroupSource.automaticNameDelimiter !== undefined
+ ? cacheGroupSource.automaticNameDelimiter
+ : this.options.automaticNameDelimiter,
+ idHint:
+ cacheGroupSource.idHint !== undefined
+ ? cacheGroupSource.idHint
+ : cacheGroupSource.key,
+ reuseExistingChunk: cacheGroupSource.reuseExistingChunk || false,
+ _validateSize: hasNonZeroSizes(minSize),
+ _validateRemainingSize: hasNonZeroSizes(minRemainingSize),
+ _minSizeForMaxSize: mergeSizes(
+ cacheGroupSource.minSize,
+ this.options.minSize
+ ),
+ _conditionalEnforce: hasNonZeroSizes(enforceSizeThreshold)
+ };
+ this._cacheGroupCache.set(cacheGroupSource, cacheGroup);
+ return cacheGroup;
+ }
+
+ /**
+ * Apply the plugin
+ * @param {Compiler} compiler the compiler instance
+ * @returns {void}
+ */
+ apply(compiler) {
+ const cachedMakePathsRelative = makePathsRelative.bindContextCache(
+ compiler.context,
+ compiler.root
+ );
+ compiler.hooks.thisCompilation.tap("SplitChunksPlugin", compilation => {
+ const logger = compilation.getLogger("webpack.SplitChunksPlugin");
+ let alreadyOptimized = false;
+ compilation.hooks.unseal.tap("SplitChunksPlugin", () => {
+ alreadyOptimized = false;
+ });
+ compilation.hooks.optimizeChunks.tap(
+ {
+ name: "SplitChunksPlugin",
+ stage: STAGE_ADVANCED
+ },
+ chunks => {
+ if (alreadyOptimized) return;
+ alreadyOptimized = true;
+ logger.time("prepare");
+ const chunkGraph = compilation.chunkGraph;
+ const moduleGraph = compilation.moduleGraph;
+ // Give each selected chunk an index (to create strings from chunks)
+ /** @type {Map<Chunk, bigint>} */
+ const chunkIndexMap = new Map();
+ const ZERO = BigInt("0");
+ const ONE = BigInt("1");
+ const START = ONE << BigInt("31");
+ let index = START;
+ for (const chunk of chunks) {
+ chunkIndexMap.set(
+ chunk,
+ index | BigInt((Math.random() * 0x7fffffff) | 0)
+ );
+ index = index << ONE;
+ }
+ /**
+ * @param {Iterable<Chunk>} chunks list of chunks
+ * @returns {bigint | Chunk} key of the chunks
+ */
+ const getKey = chunks => {
+ const iterator = chunks[Symbol.iterator]();
+ let result = iterator.next();
+ if (result.done) return ZERO;
+ const first = result.value;
+ result = iterator.next();
+ if (result.done) return first;
+ let key =
+ chunkIndexMap.get(first) | chunkIndexMap.get(result.value);
+ while (!(result = iterator.next()).done) {
+ const raw = chunkIndexMap.get(result.value);
+ key = key ^ raw;
+ }
+ return key;
+ };
+ /**
+ * @param {bigint | Chunk} key key of the chunks
+ * @returns {string} stringified key
+ */
+ const keyToString = key => {
+ if (typeof key === "bigint") return key.toString(16);
+ return chunkIndexMap.get(key).toString(16);
+ };
+
+ const getChunkSetsInGraph = memoize(() => {
+ /** @type {Map<bigint, Set<Chunk>>} */
+ const chunkSetsInGraph = new Map();
+ /** @type {Set<Chunk>} */
+ const singleChunkSets = new Set();
+ for (const module of compilation.modules) {
+ const chunks = chunkGraph.getModuleChunksIterable(module);
+ const chunksKey = getKey(chunks);
+ if (typeof chunksKey === "bigint") {
+ if (!chunkSetsInGraph.has(chunksKey)) {
+ chunkSetsInGraph.set(chunksKey, new Set(chunks));
+ }
+ } else {
+ singleChunkSets.add(chunksKey);
+ }
+ }
+ return { chunkSetsInGraph, singleChunkSets };
+ });
+
+ /**
+ * @param {Module} module the module
+ * @returns {Iterable<Chunk[]>} groups of chunks with equal exports
+ */
+ const groupChunksByExports = module => {
+ const exportsInfo = moduleGraph.getExportsInfo(module);
+ const groupedByUsedExports = new Map();
+ for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
+ const key = exportsInfo.getUsageKey(chunk.runtime);
+ const list = groupedByUsedExports.get(key);
+ if (list !== undefined) {
+ list.push(chunk);
+ } else {
+ groupedByUsedExports.set(key, [chunk]);
+ }
+ }
+ return groupedByUsedExports.values();
+ };
+
+ /** @type {Map<Module, Iterable<Chunk[]>>} */
+ const groupedByExportsMap = new Map();
+
+ const getExportsChunkSetsInGraph = memoize(() => {
+ /** @type {Map<bigint, Set<Chunk>>} */
+ const chunkSetsInGraph = new Map();
+ /** @type {Set<Chunk>} */
+ const singleChunkSets = new Set();
+ for (const module of compilation.modules) {
+ const groupedChunks = Array.from(groupChunksByExports(module));
+ groupedByExportsMap.set(module, groupedChunks);
+ for (const chunks of groupedChunks) {
+ if (chunks.length === 1) {
+ singleChunkSets.add(chunks[0]);
+ } else {
+ const chunksKey = /** @type {bigint} */ (getKey(chunks));
+ if (!chunkSetsInGraph.has(chunksKey)) {
+ chunkSetsInGraph.set(chunksKey, new Set(chunks));
+ }
+ }
+ }
+ }
+ return { chunkSetsInGraph, singleChunkSets };
+ });
+
+ // group these set of chunks by count
+ // to allow to check less sets via isSubset
+ // (only smaller sets can be subset)
+ /**
+ * @param {IterableIterator<Set<Chunk>>} chunkSets set of sets of chunks
+ * @returns {Map<number, Array<Set<Chunk>>>} map of sets of chunks by count
+ */
+ const groupChunkSetsByCount = chunkSets => {
+ /** @type {Map<number, Array<Set<Chunk>>>} */
+ const chunkSetsByCount = new Map();
+ for (const chunksSet of chunkSets) {
+ const count = chunksSet.size;
+ let array = chunkSetsByCount.get(count);
+ if (array === undefined) {
+ array = [];
+ chunkSetsByCount.set(count, array);
+ }
+ array.push(chunksSet);
+ }
+ return chunkSetsByCount;
+ };
+ const getChunkSetsByCount = memoize(() =>
+ groupChunkSetsByCount(
+ getChunkSetsInGraph().chunkSetsInGraph.values()
+ )
+ );
+ const getExportsChunkSetsByCount = memoize(() =>
+ groupChunkSetsByCount(
+ getExportsChunkSetsInGraph().chunkSetsInGraph.values()
+ )
+ );
+
+ // Create a list of possible combinations
+ const createGetCombinations = (
+ chunkSets,
+ singleChunkSets,
+ chunkSetsByCount
+ ) => {
+ /** @type {Map<bigint | Chunk, (Set<Chunk> | Chunk)[]>} */
+ const combinationsCache = new Map();
+
+ return key => {
+ const cacheEntry = combinationsCache.get(key);
+ if (cacheEntry !== undefined) return cacheEntry;
+ if (key instanceof Chunk) {
+ const result = [key];
+ combinationsCache.set(key, result);
+ return result;
+ }
+ const chunksSet = chunkSets.get(key);
+ /** @type {(Set<Chunk> | Chunk)[]} */
+ const array = [chunksSet];
+ for (const [count, setArray] of chunkSetsByCount) {
+ // "equal" is not needed because they would have been merge in the first step
+ if (count < chunksSet.size) {
+ for (const set of setArray) {
+ if (isSubset(chunksSet, set)) {
+ array.push(set);
+ }
+ }
+ }
+ }
+ for (const chunk of singleChunkSets) {
+ if (chunksSet.has(chunk)) {
+ array.push(chunk);
+ }
+ }
+ combinationsCache.set(key, array);
+ return array;
+ };
+ };
+
+ const getCombinationsFactory = memoize(() => {
+ const { chunkSetsInGraph, singleChunkSets } = getChunkSetsInGraph();
+ return createGetCombinations(
+ chunkSetsInGraph,
+ singleChunkSets,
+ getChunkSetsByCount()
+ );
+ });
+ const getCombinations = key => getCombinationsFactory()(key);
+
+ const getExportsCombinationsFactory = memoize(() => {
+ const { chunkSetsInGraph, singleChunkSets } =
+ getExportsChunkSetsInGraph();
+ return createGetCombinations(
+ chunkSetsInGraph,
+ singleChunkSets,
+ getExportsChunkSetsByCount()
+ );
+ });
+ const getExportsCombinations = key =>
+ getExportsCombinationsFactory()(key);
+
+ /**
+ * @typedef {Object} SelectedChunksResult
+ * @property {Chunk[]} chunks the list of chunks
+ * @property {bigint | Chunk} key a key of the list
+ */
+
+ /** @type {WeakMap<Set<Chunk> | Chunk, WeakMap<ChunkFilterFunction, SelectedChunksResult>>} */
+ const selectedChunksCacheByChunksSet = new WeakMap();
+
+ /**
+ * get list and key by applying the filter function to the list
+ * It is cached for performance reasons
+ * @param {Set<Chunk> | Chunk} chunks list of chunks
+ * @param {ChunkFilterFunction} chunkFilter filter function for chunks
+ * @returns {SelectedChunksResult} list and key
+ */
+ const getSelectedChunks = (chunks, chunkFilter) => {
+ let entry = selectedChunksCacheByChunksSet.get(chunks);
+ if (entry === undefined) {
+ entry = new WeakMap();
+ selectedChunksCacheByChunksSet.set(chunks, entry);
+ }
+ let entry2 =
+ /** @type {SelectedChunksResult} */
+ (entry.get(chunkFilter));
+ if (entry2 === undefined) {
+ /** @type {Chunk[]} */
+ const selectedChunks = [];
+ if (chunks instanceof Chunk) {
+ if (chunkFilter(chunks)) selectedChunks.push(chunks);
+ } else {
+ for (const chunk of chunks) {
+ if (chunkFilter(chunk)) selectedChunks.push(chunk);
+ }
+ }
+ entry2 = {
+ chunks: selectedChunks,
+ key: getKey(selectedChunks)
+ };
+ entry.set(chunkFilter, entry2);
+ }
+ return entry2;
+ };
+
+ /** @type {Map<string, boolean>} */
+ const alreadyValidatedParents = new Map();
+ /** @type {Set<string>} */
+ const alreadyReportedErrors = new Set();
+
+ // Map a list of chunks to a list of modules
+ // For the key the chunk "index" is used, the value is a SortableSet of modules
+ /** @type {Map<string, ChunksInfoItem>} */
+ const chunksInfoMap = new Map();
+
+ /**
+ * @param {CacheGroup} cacheGroup the current cache group
+ * @param {number} cacheGroupIndex the index of the cache group of ordering
+ * @param {Chunk[]} selectedChunks chunks selected for this module
+ * @param {bigint | Chunk} selectedChunksKey a key of selectedChunks
+ * @param {Module} module the current module
+ * @returns {void}
+ */
+ const addModuleToChunksInfoMap = (
+ cacheGroup,
+ cacheGroupIndex,
+ selectedChunks,
+ selectedChunksKey,
+ module
+ ) => {
+ // Break if minimum number of chunks is not reached
+ if (selectedChunks.length < cacheGroup.minChunks) return;
+ // Determine name for split chunk
+ const name =
+ /** @type {string} */
+ (cacheGroup.getName(module, selectedChunks, cacheGroup.key));
+ // Check if the name is ok
+ const existingChunk = compilation.namedChunks.get(name);
+ if (existingChunk) {
+ const parentValidationKey = `${name}|${
+ typeof selectedChunksKey === "bigint"
+ ? selectedChunksKey
+ : selectedChunksKey.debugId
+ }`;
+ const valid = alreadyValidatedParents.get(parentValidationKey);
+ if (valid === false) return;
+ if (valid === undefined) {
+ // Module can only be moved into the existing chunk if the existing chunk
+ // is a parent of all selected chunks
+ let isInAllParents = true;
+ /** @type {Set<ChunkGroup>} */
+ const queue = new Set();
+ for (const chunk of selectedChunks) {
+ for (const group of chunk.groupsIterable) {
+ queue.add(group);
+ }
+ }
+ for (const group of queue) {
+ if (existingChunk.isInGroup(group)) continue;
+ let hasParent = false;
+ for (const parent of group.parentsIterable) {
+ hasParent = true;
+ queue.add(parent);
+ }
+ if (!hasParent) {
+ isInAllParents = false;
+ }
+ }
+ const valid = isInAllParents;
+ alreadyValidatedParents.set(parentValidationKey, valid);
+ if (!valid) {
+ if (!alreadyReportedErrors.has(name)) {
+ alreadyReportedErrors.add(name);
+ compilation.errors.push(
+ new WebpackError(
+ "SplitChunksPlugin\n" +
+ `Cache group "${cacheGroup.key}" conflicts with existing chunk.\n` +
+ `Both have the same name "${name}" and existing chunk is not a parent of the selected modules.\n` +
+ "Use a different name for the cache group or make sure that the existing chunk is a parent (e. g. via dependOn).\n" +
+ 'HINT: You can omit "name" to automatically create a name.\n' +
+ "BREAKING CHANGE: webpack < 5 used to allow to use an entrypoint as splitChunk. " +
+ "This is no longer allowed when the entrypoint is not a parent of the selected modules.\n" +
+ "Remove this entrypoint and add modules to cache group's 'test' instead. " +
+ "If you need modules to be evaluated on startup, add them to the existing entrypoints (make them arrays). " +
+ "See migration guide of more info."
+ )
+ );
+ }
+ return;
+ }
+ }
+ }
+ // Create key for maps
+ // When it has a name we use the name as key
+ // Otherwise we create the key from chunks and cache group key
+ // This automatically merges equal names
+ const key =
+ cacheGroup.key +
+ (name
+ ? ` name:${name}`
+ : ` chunks:${keyToString(selectedChunksKey)}`);
+ // Add module to maps
+ let info = /** @type {ChunksInfoItem} */ (chunksInfoMap.get(key));
+ if (info === undefined) {
+ chunksInfoMap.set(
+ key,
+ (info = {
+ modules: new SortableSet(
+ undefined,
+ compareModulesByIdentifier
+ ),
+ cacheGroup,
+ cacheGroupIndex,
+ name,
+ sizes: {},
+ chunks: new Set(),
+ reuseableChunks: new Set(),
+ chunksKeys: new Set()
+ })
+ );
+ }
+ const oldSize = info.modules.size;
+ info.modules.add(module);
+ if (info.modules.size !== oldSize) {
+ for (const type of module.getSourceTypes()) {
+ info.sizes[type] = (info.sizes[type] || 0) + module.size(type);
+ }
+ }
+ const oldChunksKeysSize = info.chunksKeys.size;
+ info.chunksKeys.add(selectedChunksKey);
+ if (oldChunksKeysSize !== info.chunksKeys.size) {
+ for (const chunk of selectedChunks) {
+ info.chunks.add(chunk);
+ }
+ }
+ };
+
+ const context = {
+ moduleGraph,
+ chunkGraph
+ };
+
+ logger.timeEnd("prepare");
+
+ logger.time("modules");
+
+ // Walk through all modules
+ for (const module of compilation.modules) {
+ // Get cache group
+ let cacheGroups = this.options.getCacheGroups(module, context);
+ if (!Array.isArray(cacheGroups) || cacheGroups.length === 0) {
+ continue;
+ }
+
+ // Prepare some values (usedExports = false)
+ const getCombs = memoize(() => {
+ const chunks = chunkGraph.getModuleChunksIterable(module);
+ const chunksKey = getKey(chunks);
+ return getCombinations(chunksKey);
+ });
+
+ // Prepare some values (usedExports = true)
+ const getCombsByUsedExports = memoize(() => {
+ // fill the groupedByExportsMap
+ getExportsChunkSetsInGraph();
+ /** @type {Set<Set<Chunk> | Chunk>} */
+ const set = new Set();
+ const groupedByUsedExports =
+ /** @type {Iterable<Chunk[]>} */
+ (groupedByExportsMap.get(module));
+ for (const chunks of groupedByUsedExports) {
+ const chunksKey = getKey(chunks);
+ for (const comb of getExportsCombinations(chunksKey))
+ set.add(comb);
+ }
+ return set;
+ });
+
+ let cacheGroupIndex = 0;
+ for (const cacheGroupSource of cacheGroups) {
+ const cacheGroup = this._getCacheGroup(cacheGroupSource);
+
+ const combs = cacheGroup.usedExports
+ ? getCombsByUsedExports()
+ : getCombs();
+ // For all combination of chunk selection
+ for (const chunkCombination of combs) {
+ // Break if minimum number of chunks is not reached
+ const count =
+ chunkCombination instanceof Chunk ? 1 : chunkCombination.size;
+ if (count < cacheGroup.minChunks) continue;
+ // Select chunks by configuration
+ const { chunks: selectedChunks, key: selectedChunksKey } =
+ getSelectedChunks(
+ chunkCombination,
+ /** @type {ChunkFilterFunction} */ (cacheGroup.chunksFilter)
+ );
+
+ addModuleToChunksInfoMap(
+ cacheGroup,
+ cacheGroupIndex,
+ selectedChunks,
+ selectedChunksKey,
+ module
+ );
+ }
+ cacheGroupIndex++;
+ }
+ }
+
+ logger.timeEnd("modules");
+
+ logger.time("queue");
+
+ /**
+ * @param {ChunksInfoItem} info entry
+ * @param {string[]} sourceTypes source types to be removed
+ */
+ const removeModulesWithSourceType = (info, sourceTypes) => {
+ for (const module of info.modules) {
+ const types = module.getSourceTypes();
+ if (sourceTypes.some(type => types.has(type))) {
+ info.modules.delete(module);
+ for (const type of types) {
+ info.sizes[type] -= module.size(type);
+ }
+ }
+ }
+ };
+
+ /**
+ * @param {ChunksInfoItem} info entry
+ * @returns {boolean} true, if entry become empty
+ */
+ const removeMinSizeViolatingModules = info => {
+ if (!info.cacheGroup._validateSize) return false;
+ const violatingSizes = getViolatingMinSizes(
+ info.sizes,
+ info.cacheGroup.minSize
+ );
+ if (violatingSizes === undefined) return false;
+ removeModulesWithSourceType(info, violatingSizes);
+ return info.modules.size === 0;
+ };
+
+ // Filter items were size < minSize
+ for (const [key, info] of chunksInfoMap) {
+ if (removeMinSizeViolatingModules(info)) {
+ chunksInfoMap.delete(key);
+ } else if (
+ !checkMinSizeReduction(
+ info.sizes,
+ info.cacheGroup.minSizeReduction,
+ info.chunks.size
+ )
+ ) {
+ chunksInfoMap.delete(key);
+ }
+ }
+
+ /**
+ * @typedef {Object} MaxSizeQueueItem
+ * @property {SplitChunksSizes} minSize
+ * @property {SplitChunksSizes} maxAsyncSize
+ * @property {SplitChunksSizes} maxInitialSize
+ * @property {string} automaticNameDelimiter
+ * @property {string[]} keys
+ */
+
+ /** @type {Map<Chunk, MaxSizeQueueItem>} */
+ const maxSizeQueueMap = new Map();
+
+ while (chunksInfoMap.size > 0) {
+ // Find best matching entry
+ let bestEntryKey;
+ let bestEntry;
+ for (const pair of chunksInfoMap) {
+ const key = pair[0];
+ const info = pair[1];
+ if (
+ bestEntry === undefined ||
+ compareEntries(bestEntry, info) < 0
+ ) {
+ bestEntry = info;
+ bestEntryKey = key;
+ }
+ }
+
+ const item = /** @type {ChunksInfoItem} */ (bestEntry);
+ chunksInfoMap.delete(/** @type {string} */ (bestEntryKey));
+
+ /** @type {Chunk["name"] | undefined} */
+ let chunkName = item.name;
+ // Variable for the new chunk (lazy created)
+ /** @type {Chunk | undefined} */
+ let newChunk;
+ // When no chunk name, check if we can reuse a chunk instead of creating a new one
+ let isExistingChunk = false;
+ let isReusedWithAllModules = false;
+ if (chunkName) {
+ const chunkByName = compilation.namedChunks.get(chunkName);
+ if (chunkByName !== undefined) {
+ newChunk = chunkByName;
+ const oldSize = item.chunks.size;
+ item.chunks.delete(newChunk);
+ isExistingChunk = item.chunks.size !== oldSize;
+ }
+ } else if (item.cacheGroup.reuseExistingChunk) {
+ outer: for (const chunk of item.chunks) {
+ if (
+ chunkGraph.getNumberOfChunkModules(chunk) !==
+ item.modules.size
+ ) {
+ continue;
+ }
+ if (
+ item.chunks.size > 1 &&
+ chunkGraph.getNumberOfEntryModules(chunk) > 0
+ ) {
+ continue;
+ }
+ for (const module of item.modules) {
+ if (!chunkGraph.isModuleInChunk(module, chunk)) {
+ continue outer;
+ }
+ }
+ if (!newChunk || !newChunk.name) {
+ newChunk = chunk;
+ } else if (
+ chunk.name &&
+ chunk.name.length < newChunk.name.length
+ ) {
+ newChunk = chunk;
+ } else if (
+ chunk.name &&
+ chunk.name.length === newChunk.name.length &&
+ chunk.name < newChunk.name
+ ) {
+ newChunk = chunk;
+ }
+ }
+ if (newChunk) {
+ item.chunks.delete(newChunk);
+ chunkName = undefined;
+ isExistingChunk = true;
+ isReusedWithAllModules = true;
+ }
+ }
+
+ const enforced =
+ item.cacheGroup._conditionalEnforce &&
+ checkMinSize(item.sizes, item.cacheGroup.enforceSizeThreshold);
+
+ const usedChunks = new Set(item.chunks);
+
+ // Check if maxRequests condition can be fulfilled
+ if (
+ !enforced &&
+ (Number.isFinite(item.cacheGroup.maxInitialRequests) ||
+ Number.isFinite(item.cacheGroup.maxAsyncRequests))
+ ) {
+ for (const chunk of usedChunks) {
+ // respect max requests
+ const maxRequests = /** @type {number} */ (
+ chunk.isOnlyInitial()
+ ? item.cacheGroup.maxInitialRequests
+ : chunk.canBeInitial()
+ ? Math.min(
+ /** @type {number} */
+ (item.cacheGroup.maxInitialRequests),
+ /** @type {number} */
+ (item.cacheGroup.maxAsyncRequests)
+ )
+ : item.cacheGroup.maxAsyncRequests
+ );
+ if (
+ isFinite(maxRequests) &&
+ getRequests(chunk) >= maxRequests
+ ) {
+ usedChunks.delete(chunk);
+ }
+ }
+ }
+
+ outer: for (const chunk of usedChunks) {
+ for (const module of item.modules) {
+ if (chunkGraph.isModuleInChunk(module, chunk)) continue outer;
+ }
+ usedChunks.delete(chunk);
+ }
+
+ // Were some (invalid) chunks removed from usedChunks?
+ // => readd all modules to the queue, as things could have been changed
+ if (usedChunks.size < item.chunks.size) {
+ if (isExistingChunk)
+ usedChunks.add(/** @type {Chunk} */ (newChunk));
+ if (
+ /** @type {number} */ (usedChunks.size) >=
+ /** @type {number} */ (item.cacheGroup.minChunks)
+ ) {
+ const chunksArr = Array.from(usedChunks);
+ for (const module of item.modules) {
+ addModuleToChunksInfoMap(
+ item.cacheGroup,
+ item.cacheGroupIndex,
+ chunksArr,
+ getKey(usedChunks),
+ module
+ );
+ }
+ }
+ continue;
+ }
+
+ // Validate minRemainingSize constraint when a single chunk is left over
+ if (
+ !enforced &&
+ item.cacheGroup._validateRemainingSize &&
+ usedChunks.size === 1
+ ) {
+ const [chunk] = usedChunks;
+ let chunkSizes = Object.create(null);
+ for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
+ if (!item.modules.has(module)) {
+ for (const type of module.getSourceTypes()) {
+ chunkSizes[type] =
+ (chunkSizes[type] || 0) + module.size(type);
+ }
+ }
+ }
+ const violatingSizes = getViolatingMinSizes(
+ chunkSizes,
+ item.cacheGroup.minRemainingSize
+ );
+ if (violatingSizes !== undefined) {
+ const oldModulesSize = item.modules.size;
+ removeModulesWithSourceType(item, violatingSizes);
+ if (
+ item.modules.size > 0 &&
+ item.modules.size !== oldModulesSize
+ ) {
+ // queue this item again to be processed again
+ // without violating modules
+ chunksInfoMap.set(/** @type {string} */ (bestEntryKey), item);
+ }
+ continue;
+ }
+ }
+
+ // Create the new chunk if not reusing one
+ if (newChunk === undefined) {
+ newChunk = compilation.addChunk(chunkName);
+ }
+ // Walk through all chunks
+ for (const chunk of usedChunks) {
+ // Add graph connections for splitted chunk
+ chunk.split(newChunk);
+ }
+
+ // Add a note to the chunk
+ newChunk.chunkReason =
+ (newChunk.chunkReason ? newChunk.chunkReason + ", " : "") +
+ (isReusedWithAllModules
+ ? "reused as split chunk"
+ : "split chunk");
+ if (item.cacheGroup.key) {
+ newChunk.chunkReason += ` (cache group: ${item.cacheGroup.key})`;
+ }
+ if (chunkName) {
+ newChunk.chunkReason += ` (name: ${chunkName})`;
+ }
+ if (item.cacheGroup.filename) {
+ newChunk.filenameTemplate = item.cacheGroup.filename;
+ }
+ if (item.cacheGroup.idHint) {
+ newChunk.idNameHints.add(item.cacheGroup.idHint);
+ }
+ if (!isReusedWithAllModules) {
+ // Add all modules to the new chunk
+ for (const module of item.modules) {
+ if (!module.chunkCondition(newChunk, compilation)) continue;
+ // Add module to new chunk
+ chunkGraph.connectChunkAndModule(newChunk, module);
+ // Remove module from used chunks
+ for (const chunk of usedChunks) {
+ chunkGraph.disconnectChunkAndModule(chunk, module);
+ }
+ }
+ } else {
+ // Remove all modules from used chunks
+ for (const module of item.modules) {
+ for (const chunk of usedChunks) {
+ chunkGraph.disconnectChunkAndModule(chunk, module);
+ }
+ }
+ }
+
+ if (
+ Object.keys(item.cacheGroup.maxAsyncSize).length > 0 ||
+ Object.keys(item.cacheGroup.maxInitialSize).length > 0
+ ) {
+ const oldMaxSizeSettings = maxSizeQueueMap.get(newChunk);
+ maxSizeQueueMap.set(newChunk, {
+ minSize: oldMaxSizeSettings
+ ? combineSizes(
+ oldMaxSizeSettings.minSize,
+ item.cacheGroup._minSizeForMaxSize,
+ Math.max
+ )
+ : item.cacheGroup.minSize,
+ maxAsyncSize: oldMaxSizeSettings
+ ? combineSizes(
+ oldMaxSizeSettings.maxAsyncSize,
+ item.cacheGroup.maxAsyncSize,
+ Math.min
+ )
+ : item.cacheGroup.maxAsyncSize,
+ maxInitialSize: oldMaxSizeSettings
+ ? combineSizes(
+ oldMaxSizeSettings.maxInitialSize,
+ item.cacheGroup.maxInitialSize,
+ Math.min
+ )
+ : item.cacheGroup.maxInitialSize,
+ automaticNameDelimiter: item.cacheGroup.automaticNameDelimiter,
+ keys: oldMaxSizeSettings
+ ? oldMaxSizeSettings.keys.concat(item.cacheGroup.key)
+ : [item.cacheGroup.key]
+ });
+ }
+
+ // remove all modules from other entries and update size
+ for (const [key, info] of chunksInfoMap) {
+ if (isOverlap(info.chunks, usedChunks)) {
+ // update modules and total size
+ // may remove it from the map when < minSize
+ let updated = false;
+ for (const module of item.modules) {
+ if (info.modules.has(module)) {
+ // remove module
+ info.modules.delete(module);
+ // update size
+ for (const key of module.getSourceTypes()) {
+ info.sizes[key] -= module.size(key);
+ }
+ updated = true;
+ }
+ }
+ if (updated) {
+ if (info.modules.size === 0) {
+ chunksInfoMap.delete(key);
+ continue;
+ }
+ if (
+ removeMinSizeViolatingModules(info) ||
+ !checkMinSizeReduction(
+ info.sizes,
+ info.cacheGroup.minSizeReduction,
+ info.chunks.size
+ )
+ ) {
+ chunksInfoMap.delete(key);
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ logger.timeEnd("queue");
+
+ logger.time("maxSize");
+
+ /** @type {Set<string>} */
+ const incorrectMinMaxSizeSet = new Set();
+
+ const { outputOptions } = compilation;
+
+ // Make sure that maxSize is fulfilled
+ const { fallbackCacheGroup } = this.options;
+ for (const chunk of Array.from(compilation.chunks)) {
+ const chunkConfig = maxSizeQueueMap.get(chunk);
+ const {
+ minSize,
+ maxAsyncSize,
+ maxInitialSize,
+ automaticNameDelimiter
+ } = chunkConfig || fallbackCacheGroup;
+ if (!chunkConfig && !fallbackCacheGroup.chunksFilter(chunk))
+ continue;
+ /** @type {SplitChunksSizes} */
+ let maxSize;
+ if (chunk.isOnlyInitial()) {
+ maxSize = maxInitialSize;
+ } else if (chunk.canBeInitial()) {
+ maxSize = combineSizes(maxAsyncSize, maxInitialSize, Math.min);
+ } else {
+ maxSize = maxAsyncSize;
+ }
+ if (Object.keys(maxSize).length === 0) {
+ continue;
+ }
+ for (const key of Object.keys(maxSize)) {
+ const maxSizeValue = maxSize[key];
+ const minSizeValue = minSize[key];
+ if (
+ typeof minSizeValue === "number" &&
+ minSizeValue > maxSizeValue
+ ) {
+ const keys = chunkConfig && chunkConfig.keys;
+ const warningKey = `${
+ keys && keys.join()
+ } ${minSizeValue} ${maxSizeValue}`;
+ if (!incorrectMinMaxSizeSet.has(warningKey)) {
+ incorrectMinMaxSizeSet.add(warningKey);
+ compilation.warnings.push(
+ new MinMaxSizeWarning(keys, minSizeValue, maxSizeValue)
+ );
+ }
+ }
+ }
+ const results = deterministicGroupingForModules({
+ minSize,
+ maxSize: mapObject(maxSize, (value, key) => {
+ const minSizeValue = minSize[key];
+ return typeof minSizeValue === "number"
+ ? Math.max(value, minSizeValue)
+ : value;
+ }),
+ items: chunkGraph.getChunkModulesIterable(chunk),
+ getKey(module) {
+ const cache = getKeyCache.get(module);
+ if (cache !== undefined) return cache;
+ const ident = cachedMakePathsRelative(module.identifier());
+ const nameForCondition =
+ module.nameForCondition && module.nameForCondition();
+ const name = nameForCondition
+ ? cachedMakePathsRelative(nameForCondition)
+ : ident.replace(/^.*!|\?[^?!]*$/g, "");
+ const fullKey =
+ name +
+ automaticNameDelimiter +
+ hashFilename(ident, outputOptions);
+ const key = requestToId(fullKey);
+ getKeyCache.set(module, key);
+ return key;
+ },
+ getSize(module) {
+ const size = Object.create(null);
+ for (const key of module.getSourceTypes()) {
+ size[key] = module.size(key);
+ }
+ return size;
+ }
+ });
+ if (results.length <= 1) {
+ continue;
+ }
+ for (let i = 0; i < results.length; i++) {
+ const group = results[i];
+ const key = this.options.hidePathInfo
+ ? hashFilename(group.key, outputOptions)
+ : group.key;
+ let name = chunk.name
+ ? chunk.name + automaticNameDelimiter + key
+ : null;
+ if (name && name.length > 100) {
+ name =
+ name.slice(0, 100) +
+ automaticNameDelimiter +
+ hashFilename(name, outputOptions);
+ }
+ if (i !== results.length - 1) {
+ const newPart = compilation.addChunk(
+ /** @type {Chunk["name"]} */ (name)
+ );
+ chunk.split(newPart);
+ newPart.chunkReason = chunk.chunkReason;
+ // Add all modules to the new chunk
+ for (const module of group.items) {
+ if (!module.chunkCondition(newPart, compilation)) {
+ continue;
+ }
+ // Add module to new chunk
+ chunkGraph.connectChunkAndModule(newPart, module);
+ // Remove module from used chunks
+ chunkGraph.disconnectChunkAndModule(chunk, module);
+ }
+ } else {
+ // change the chunk to be a part
+ chunk.name = /** @type {Chunk["name"]} */ (name);
+ }
+ }
+ }
+ logger.timeEnd("maxSize");
+ }
+ );
+ });
+ }
+};