summaryrefslogtreecommitdiffstats
path: root/node_modules/webpack/lib/Compilation.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/Compilation.js')
-rw-r--r--node_modules/webpack/lib/Compilation.js2327
1 files changed, 2327 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/Compilation.js b/node_modules/webpack/lib/Compilation.js
new file mode 100644
index 0000000..6329174
--- /dev/null
+++ b/node_modules/webpack/lib/Compilation.js
@@ -0,0 +1,2327 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+ */
+"use strict";
+
+const asyncLib = require("neo-async");
+const util = require("util");
+const { CachedSource } = require("webpack-sources");
+const {
+ Tapable,
+ SyncHook,
+ SyncBailHook,
+ SyncWaterfallHook,
+ AsyncSeriesHook
+} = require("tapable");
+const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
+const ModuleNotFoundError = require("./ModuleNotFoundError");
+const ModuleDependencyWarning = require("./ModuleDependencyWarning");
+const ModuleDependencyError = require("./ModuleDependencyError");
+const ChunkGroup = require("./ChunkGroup");
+const Chunk = require("./Chunk");
+const Entrypoint = require("./Entrypoint");
+const MainTemplate = require("./MainTemplate");
+const ChunkTemplate = require("./ChunkTemplate");
+const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
+const ModuleTemplate = require("./ModuleTemplate");
+const RuntimeTemplate = require("./RuntimeTemplate");
+const ChunkRenderError = require("./ChunkRenderError");
+const Stats = require("./Stats");
+const Semaphore = require("./util/Semaphore");
+const createHash = require("./util/createHash");
+const SortableSet = require("./util/SortableSet");
+const GraphHelpers = require("./GraphHelpers");
+const ModuleDependency = require("./dependencies/ModuleDependency");
+const compareLocations = require("./compareLocations");
+const { Logger, LogType } = require("./logging/Logger");
+const ErrorHelpers = require("./ErrorHelpers");
+const buildChunkGraph = require("./buildChunkGraph");
+const WebpackError = require("./WebpackError");
+
+/** @typedef {import("./Module")} Module */
+/** @typedef {import("./Compiler")} Compiler */
+/** @typedef {import("webpack-sources").Source} Source */
+/** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */
+/** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */
+/** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */
+/** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
+/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
+/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
+/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
+/** @typedef {import("./Dependency")} Dependency */
+/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
+/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
+/** @typedef {import("./util/createHash").Hash} Hash */
+
+// TODO use @callback
+/** @typedef {{[assetName: string]: Source}} CompilationAssets */
+/** @typedef {(err: Error|null, result?: Module) => void } ModuleCallback */
+/** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */
+/** @typedef {(module: Module) => void} OnModuleCallback */
+/** @typedef {(err?: Error|null) => void} Callback */
+/** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
+/** @typedef {new (...args: any[]) => Dependency} DepConstructor */
+/** @typedef {{apply: () => void}} Plugin */
+
+/**
+ * @typedef {Object} ModuleFactoryCreateDataContextInfo
+ * @property {string} issuer
+ * @property {string} compiler
+ */
+
+/**
+ * @typedef {Object} ModuleFactoryCreateData
+ * @property {ModuleFactoryCreateDataContextInfo} contextInfo
+ * @property {any=} resolveOptions
+ * @property {string} context
+ * @property {Dependency[]} dependencies
+ */
+
+/**
+ * @typedef {Object} ModuleFactory
+ * @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
+ */
+
+/**
+ * @typedef {Object} SortedDependency
+ * @property {ModuleFactory} factory
+ * @property {Dependency[]} dependencies
+ */
+
+/**
+ * @typedef {Object} DependenciesBlockLike
+ * @property {Dependency[]} dependencies
+ * @property {AsyncDependenciesBlock[]} blocks
+ * @property {DependenciesBlockVariable[]} variables
+ */
+
+/**
+ * @typedef {Object} LogEntry
+ * @property {string} type
+ * @property {any[]} args
+ * @property {number} time
+ * @property {string[]=} trace
+ */
+
+/**
+ * @typedef {Object} AssetInfo
+ * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash)
+ * @property {number=} size size in bytes, only set after asset has been emitted
+ * @property {boolean=} development true, when asset is only used for development and doesn't count towards user-facing assets
+ * @property {boolean=} hotModuleReplacement true, when asset ships data for updating an existing application (HMR)
+ */
+
+/**
+ * @typedef {Object} Asset
+ * @property {string} name the filename of the asset
+ * @property {Source} source source of the asset
+ * @property {AssetInfo} info info about the asset
+ */
+
+/**
+ * @param {Chunk} a first chunk to sort by id
+ * @param {Chunk} b second chunk to sort by id
+ * @returns {-1|0|1} sort value
+ */
+const byId = (a, b) => {
+ if (typeof a.id !== typeof b.id) {
+ return typeof a.id < typeof b.id ? -1 : 1;
+ }
+ if (a.id < b.id) return -1;
+ if (a.id > b.id) return 1;
+ return 0;
+};
+
+/**
+ * @param {Module} a first module to sort by
+ * @param {Module} b second module to sort by
+ * @returns {-1|0|1} sort value
+ */
+const byIdOrIdentifier = (a, b) => {
+ if (typeof a.id !== typeof b.id) {
+ return typeof a.id < typeof b.id ? -1 : 1;
+ }
+ if (a.id < b.id) return -1;
+ if (a.id > b.id) return 1;
+ const identA = a.identifier();
+ const identB = b.identifier();
+ if (identA < identB) return -1;
+ if (identA > identB) return 1;
+ return 0;
+};
+
+/**
+ * @param {Module} a first module to sort by
+ * @param {Module} b second module to sort by
+ * @returns {-1|0|1} sort value
+ */
+const byIndexOrIdentifier = (a, b) => {
+ if (a.index < b.index) return -1;
+ if (a.index > b.index) return 1;
+ const identA = a.identifier();
+ const identB = b.identifier();
+ if (identA < identB) return -1;
+ if (identA > identB) return 1;
+ return 0;
+};
+
+/**
+ * @param {Compilation} a first compilation to sort by
+ * @param {Compilation} b second compilation to sort by
+ * @returns {-1|0|1} sort value
+ */
+const byNameOrHash = (a, b) => {
+ if (a.name < b.name) return -1;
+ if (a.name > b.name) return 1;
+ if (a.fullHash < b.fullHash) return -1;
+ if (a.fullHash > b.fullHash) return 1;
+ return 0;
+};
+
+/**
+ * @param {DependenciesBlockVariable[]} variables DepBlock Variables to iterate over
+ * @param {DepBlockVarDependenciesCallback} fn callback to apply on iterated elements
+ * @returns {void}
+ */
+const iterationBlockVariable = (variables, fn) => {
+ for (
+ let indexVariable = 0;
+ indexVariable < variables.length;
+ indexVariable++
+ ) {
+ const varDep = variables[indexVariable].dependencies;
+ for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) {
+ fn(varDep[indexVDep]);
+ }
+ }
+};
+
+/**
+ * @template T
+ * @param {T[]} arr array of elements to iterate over
+ * @param {function(T): void} fn callback applied to each element
+ * @returns {void}
+ */
+const iterationOfArrayCallback = (arr, fn) => {
+ for (let index = 0; index < arr.length; index++) {
+ fn(arr[index]);
+ }
+};
+
+/**
+ * @template T
+ * @param {Set<T>} set set to add items to
+ * @param {Set<T>} otherSet set to add items from
+ * @returns {void}
+ */
+const addAllToSet = (set, otherSet) => {
+ for (const item of otherSet) {
+ set.add(item);
+ }
+};
+
+/**
+ * @param {Source} a a source
+ * @param {Source} b another source
+ * @returns {boolean} true, when both sources are equal
+ */
+const isSourceEqual = (a, b) => {
+ if (a === b) return true;
+ // TODO webpack 5: check .buffer() instead, it's called anyway during emit
+ /** @type {Buffer|string} */
+ let aSource = a.source();
+ /** @type {Buffer|string} */
+ let bSource = b.source();
+ if (aSource === bSource) return true;
+ if (typeof aSource === "string" && typeof bSource === "string") return false;
+ if (!Buffer.isBuffer(aSource)) aSource = Buffer.from(aSource, "utf-8");
+ if (!Buffer.isBuffer(bSource)) bSource = Buffer.from(bSource, "utf-8");
+ return aSource.equals(bSource);
+};
+
+class Compilation extends Tapable {
+ /**
+ * Creates an instance of Compilation.
+ * @param {Compiler} compiler the compiler which created the compilation
+ */
+ constructor(compiler) {
+ super();
+ this.hooks = {
+ /** @type {SyncHook<Module>} */
+ buildModule: new SyncHook(["module"]),
+ /** @type {SyncHook<Module>} */
+ rebuildModule: new SyncHook(["module"]),
+ /** @type {SyncHook<Module, Error>} */
+ failedModule: new SyncHook(["module", "error"]),
+ /** @type {SyncHook<Module>} */
+ succeedModule: new SyncHook(["module"]),
+
+ /** @type {SyncHook<Dependency, string>} */
+ addEntry: new SyncHook(["entry", "name"]),
+ /** @type {SyncHook<Dependency, string, Error>} */
+ failedEntry: new SyncHook(["entry", "name", "error"]),
+ /** @type {SyncHook<Dependency, string, Module>} */
+ succeedEntry: new SyncHook(["entry", "name", "module"]),
+
+ /** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
+ dependencyReference: new SyncWaterfallHook([
+ "dependencyReference",
+ "dependency",
+ "module"
+ ]),
+
+ /** @type {AsyncSeriesHook<Module[]>} */
+ finishModules: new AsyncSeriesHook(["modules"]),
+ /** @type {SyncHook<Module>} */
+ finishRebuildingModule: new SyncHook(["module"]),
+ /** @type {SyncHook} */
+ unseal: new SyncHook([]),
+ /** @type {SyncHook} */
+ seal: new SyncHook([]),
+
+ /** @type {SyncHook} */
+ beforeChunks: new SyncHook([]),
+ /** @type {SyncHook<Chunk[]>} */
+ afterChunks: new SyncHook(["chunks"]),
+
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeDependenciesBasic: new SyncBailHook(["modules"]),
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeDependencies: new SyncBailHook(["modules"]),
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeDependenciesAdvanced: new SyncBailHook(["modules"]),
+ /** @type {SyncBailHook<Module[]>} */
+ afterOptimizeDependencies: new SyncHook(["modules"]),
+
+ /** @type {SyncHook} */
+ optimize: new SyncHook([]),
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeModulesBasic: new SyncBailHook(["modules"]),
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeModules: new SyncBailHook(["modules"]),
+ /** @type {SyncBailHook<Module[]>} */
+ optimizeModulesAdvanced: new SyncBailHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ afterOptimizeModules: new SyncHook(["modules"]),
+
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
+ optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]),
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
+ optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
+ optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]),
+ /** @type {SyncHook<Chunk[], ChunkGroup[]>} */
+ afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
+
+ /** @type {AsyncSeriesHook<Chunk[], Module[]>} */
+ optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
+ /** @type {SyncHook<Chunk[], Module[]>} */
+ afterOptimizeTree: new SyncHook(["chunks", "modules"]),
+
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
+ optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]),
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
+ optimizeChunkModules: new SyncBailHook(["chunks", "modules"]),
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
+ optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]),
+ /** @type {SyncHook<Chunk[], Module[]>} */
+ afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
+ /** @type {SyncBailHook} */
+ shouldRecord: new SyncBailHook([]),
+
+ /** @type {SyncHook<Module[], any>} */
+ reviveModules: new SyncHook(["modules", "records"]),
+ /** @type {SyncHook<Module[]>} */
+ optimizeModuleOrder: new SyncHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ advancedOptimizeModuleOrder: new SyncHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ beforeModuleIds: new SyncHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ moduleIds: new SyncHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ optimizeModuleIds: new SyncHook(["modules"]),
+ /** @type {SyncHook<Module[]>} */
+ afterOptimizeModuleIds: new SyncHook(["modules"]),
+
+ /** @type {SyncHook<Chunk[], any>} */
+ reviveChunks: new SyncHook(["chunks", "records"]),
+ /** @type {SyncHook<Chunk[]>} */
+ optimizeChunkOrder: new SyncHook(["chunks"]),
+ /** @type {SyncHook<Chunk[]>} */
+ beforeChunkIds: new SyncHook(["chunks"]),
+ /** @type {SyncHook<Chunk[]>} */
+ optimizeChunkIds: new SyncHook(["chunks"]),
+ /** @type {SyncHook<Chunk[]>} */
+ afterOptimizeChunkIds: new SyncHook(["chunks"]),
+
+ /** @type {SyncHook<Module[], any>} */
+ recordModules: new SyncHook(["modules", "records"]),
+ /** @type {SyncHook<Chunk[], any>} */
+ recordChunks: new SyncHook(["chunks", "records"]),
+
+ /** @type {SyncHook} */
+ beforeHash: new SyncHook([]),
+ /** @type {SyncHook<Chunk>} */
+ contentHash: new SyncHook(["chunk"]),
+ /** @type {SyncHook} */
+ afterHash: new SyncHook([]),
+ /** @type {SyncHook<any>} */
+ recordHash: new SyncHook(["records"]),
+ /** @type {SyncHook<Compilation, any>} */
+ record: new SyncHook(["compilation", "records"]),
+
+ /** @type {SyncHook} */
+ beforeModuleAssets: new SyncHook([]),
+ /** @type {SyncBailHook} */
+ shouldGenerateChunkAssets: new SyncBailHook([]),
+ /** @type {SyncHook} */
+ beforeChunkAssets: new SyncHook([]),
+ /** @type {SyncHook<Chunk[]>} */
+ additionalChunkAssets: new SyncHook(["chunks"]),
+
+ /** @type {AsyncSeriesHook} */
+ additionalAssets: new AsyncSeriesHook([]),
+ /** @type {AsyncSeriesHook<Chunk[]>} */
+ optimizeChunkAssets: new AsyncSeriesHook(["chunks"]),
+ /** @type {SyncHook<Chunk[]>} */
+ afterOptimizeChunkAssets: new SyncHook(["chunks"]),
+ /** @type {AsyncSeriesHook<CompilationAssets>} */
+ optimizeAssets: new AsyncSeriesHook(["assets"]),
+ /** @type {SyncHook<CompilationAssets>} */
+ afterOptimizeAssets: new SyncHook(["assets"]),
+
+ /** @type {SyncBailHook} */
+ needAdditionalSeal: new SyncBailHook([]),
+ /** @type {AsyncSeriesHook} */
+ afterSeal: new AsyncSeriesHook([]),
+
+ /** @type {SyncHook<Chunk, Hash>} */
+ chunkHash: new SyncHook(["chunk", "chunkHash"]),
+ /** @type {SyncHook<Module, string>} */
+ moduleAsset: new SyncHook(["module", "filename"]),
+ /** @type {SyncHook<Chunk, string>} */
+ chunkAsset: new SyncHook(["chunk", "filename"]),
+
+ /** @type {SyncWaterfallHook<string, TODO>} */
+ assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate
+
+ /** @type {SyncBailHook} */
+ needAdditionalPass: new SyncBailHook([]),
+
+ /** @type {SyncHook<Compiler, string, number>} */
+ childCompiler: new SyncHook([
+ "childCompiler",
+ "compilerName",
+ "compilerIndex"
+ ]),
+
+ /** @type {SyncBailHook<string, LogEntry>} */
+ log: new SyncBailHook(["origin", "logEntry"]),
+
+ // TODO the following hooks are weirdly located here
+ // TODO move them for webpack 5
+ /** @type {SyncHook<object, Module>} */
+ normalModuleLoader: new SyncHook(["loaderContext", "module"]),
+
+ /** @type {SyncBailHook<Chunk[]>} */
+ optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]),
+ /** @type {SyncBailHook<Chunk[]>} */
+ optimizeExtractedChunks: new SyncBailHook(["chunks"]),
+ /** @type {SyncBailHook<Chunk[]>} */
+ optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]),
+ /** @type {SyncHook<Chunk[]>} */
+ afterOptimizeExtractedChunks: new SyncHook(["chunks"])
+ };
+ this._pluginCompat.tap("Compilation", options => {
+ switch (options.name) {
+ case "optimize-tree":
+ case "additional-assets":
+ case "optimize-chunk-assets":
+ case "optimize-assets":
+ case "after-seal":
+ options.async = true;
+ break;
+ }
+ });
+ /** @type {string=} */
+ this.name = undefined;
+ /** @type {Compiler} */
+ this.compiler = compiler;
+ this.resolverFactory = compiler.resolverFactory;
+ this.inputFileSystem = compiler.inputFileSystem;
+ this.requestShortener = compiler.requestShortener;
+
+ const options = compiler.options;
+ this.options = options;
+ this.outputOptions = options && options.output;
+ /** @type {boolean=} */
+ this.bail = options && options.bail;
+ this.profile = options && options.profile;
+ this.performance = options && options.performance;
+
+ this.mainTemplate = new MainTemplate(this.outputOptions);
+ this.chunkTemplate = new ChunkTemplate(this.outputOptions);
+ this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(
+ this.outputOptions
+ );
+ this.runtimeTemplate = new RuntimeTemplate(
+ this.outputOptions,
+ this.requestShortener
+ );
+ this.moduleTemplates = {
+ javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
+ webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
+ };
+
+ this.semaphore = new Semaphore(options.parallelism || 100);
+
+ this.entries = [];
+ /** @private @type {{name: string, request: string, module: Module}[]} */
+ this._preparedEntrypoints = [];
+ /** @type {Map<string, Entrypoint>} */
+ this.entrypoints = new Map();
+ /** @type {Chunk[]} */
+ this.chunks = [];
+ /** @type {ChunkGroup[]} */
+ this.chunkGroups = [];
+ /** @type {Map<string, ChunkGroup>} */
+ this.namedChunkGroups = new Map();
+ /** @type {Map<string, Chunk>} */
+ this.namedChunks = new Map();
+ /** @type {Module[]} */
+ this.modules = [];
+ /** @private @type {Map<string, Module>} */
+ this._modules = new Map();
+ this.cache = null;
+ this.records = null;
+ /** @type {string[]} */
+ this.additionalChunkAssets = [];
+ /** @type {CompilationAssets} */
+ this.assets = {};
+ /** @type {Map<string, AssetInfo>} */
+ this.assetsInfo = new Map();
+ /** @type {WebpackError[]} */
+ this.errors = [];
+ /** @type {WebpackError[]} */
+ this.warnings = [];
+ /** @type {Compilation[]} */
+ this.children = [];
+ /** @type {Map<string, LogEntry[]>} */
+ this.logging = new Map();
+ /** @type {Map<DepConstructor, ModuleFactory>} */
+ this.dependencyFactories = new Map();
+ /** @type {Map<DepConstructor, DependencyTemplate>} */
+ this.dependencyTemplates = new Map();
+ // TODO refactor this in webpack 5 to a custom DependencyTemplates class with a hash property
+ // @ts-ignore
+ this.dependencyTemplates.set("hash", "");
+ this.childrenCounters = {};
+ /** @type {Set<number|string>} */
+ this.usedChunkIds = null;
+ /** @type {Set<number>} */
+ this.usedModuleIds = null;
+ /** @type {Map<string, number>=} */
+ this.fileTimestamps = undefined;
+ /** @type {Map<string, number>=} */
+ this.contextTimestamps = undefined;
+ /** @type {Set<string>=} */
+ this.compilationDependencies = undefined;
+ /** @private @type {Map<Module, Callback[]>} */
+ this._buildingModules = new Map();
+ /** @private @type {Map<Module, Callback[]>} */
+ this._rebuildingModules = new Map();
+ /** @type {Set<string>} */
+ this.emittedAssets = new Set();
+ }
+
+ getStats() {
+ return new Stats(this);
+ }
+
+ /**
+ * @param {string | (function(): string)} name name of the logger, or function called once to get the logger name
+ * @returns {Logger} a logger with that name
+ */
+ getLogger(name) {
+ if (!name) {
+ throw new TypeError("Compilation.getLogger(name) called without a name");
+ }
+ /** @type {LogEntry[] | undefined} */
+ let logEntries;
+ return new Logger((type, args) => {
+ if (typeof name === "function") {
+ name = name();
+ if (!name) {
+ throw new TypeError(
+ "Compilation.getLogger(name) called with a function not returning a name"
+ );
+ }
+ }
+ let trace;
+ switch (type) {
+ case LogType.warn:
+ case LogType.error:
+ case LogType.trace:
+ trace = ErrorHelpers.cutOffLoaderExecution(new Error("Trace").stack)
+ .split("\n")
+ .slice(3);
+ break;
+ }
+ /** @type {LogEntry} */
+ const logEntry = {
+ time: Date.now(),
+ type,
+ args,
+ trace
+ };
+ if (this.hooks.log.call(name, logEntry) === undefined) {
+ if (logEntry.type === LogType.profileEnd) {
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
+ if (typeof console.profileEnd === "function") {
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
+ console.profileEnd(`[${name}] ${logEntry.args[0]}`);
+ }
+ }
+ if (logEntries === undefined) {
+ logEntries = this.logging.get(name);
+ if (logEntries === undefined) {
+ logEntries = [];
+ this.logging.set(name, logEntries);
+ }
+ }
+ logEntries.push(logEntry);
+ if (logEntry.type === LogType.profile) {
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
+ if (typeof console.profile === "function") {
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
+ console.profile(`[${name}] ${logEntry.args[0]}`);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * @typedef {Object} AddModuleResult
+ * @property {Module} module the added or existing module
+ * @property {boolean} issuer was this the first request for this module
+ * @property {boolean} build should the module be build
+ * @property {boolean} dependencies should dependencies be walked
+ */
+
+ /**
+ * @param {Module} module module to be added that was created
+ * @param {any=} cacheGroup cacheGroup it is apart of
+ * @returns {AddModuleResult} returns meta about whether or not the module had built
+ * had an issuer, or any dependnecies
+ */
+ addModule(module, cacheGroup) {
+ const identifier = module.identifier();
+ const alreadyAddedModule = this._modules.get(identifier);
+ if (alreadyAddedModule) {
+ return {
+ module: alreadyAddedModule,
+ issuer: false,
+ build: false,
+ dependencies: false
+ };
+ }
+ const cacheName = (cacheGroup || "m") + identifier;
+ if (this.cache && this.cache[cacheName]) {
+ const cacheModule = this.cache[cacheName];
+
+ if (typeof cacheModule.updateCacheModule === "function") {
+ cacheModule.updateCacheModule(module);
+ }
+
+ let rebuild = true;
+ if (this.fileTimestamps && this.contextTimestamps) {
+ rebuild = cacheModule.needRebuild(
+ this.fileTimestamps,
+ this.contextTimestamps
+ );
+ }
+
+ if (!rebuild) {
+ cacheModule.disconnect();
+ this._modules.set(identifier, cacheModule);
+ this.modules.push(cacheModule);
+ for (const err of cacheModule.errors) {
+ this.errors.push(err);
+ }
+ for (const err of cacheModule.warnings) {
+ this.warnings.push(err);
+ }
+ return {
+ module: cacheModule,
+ issuer: true,
+ build: false,
+ dependencies: true
+ };
+ }
+ cacheModule.unbuild();
+ module = cacheModule;
+ }
+ this._modules.set(identifier, module);
+ if (this.cache) {
+ this.cache[cacheName] = module;
+ }
+ this.modules.push(module);
+ return {
+ module: module,
+ issuer: true,
+ build: true,
+ dependencies: true
+ };
+ }
+
+ /**
+ * Fetches a module from a compilation by its identifier
+ * @param {Module} module the module provided
+ * @returns {Module} the module requested
+ */
+ getModule(module) {
+ const identifier = module.identifier();
+ return this._modules.get(identifier);
+ }
+
+ /**
+ * Attempts to search for a module by its identifier
+ * @param {string} identifier identifier (usually path) for module
+ * @returns {Module|undefined} attempt to search for module and return it, else undefined
+ */
+ findModule(identifier) {
+ return this._modules.get(identifier);
+ }
+
+ /**
+ * @param {Module} module module with its callback list
+ * @param {Callback} callback the callback function
+ * @returns {void}
+ */
+ waitForBuildingFinished(module, callback) {
+ let callbackList = this._buildingModules.get(module);
+ if (callbackList) {
+ callbackList.push(() => callback());
+ } else {
+ process.nextTick(callback);
+ }
+ }
+
+ /**
+ * Builds the module object
+ *
+ * @param {Module} module module to be built
+ * @param {boolean} optional optional flag
+ * @param {Module=} origin origin module this module build was requested from
+ * @param {Dependency[]=} dependencies optional dependencies from the module to be built
+ * @param {TODO} thisCallback the callback
+ * @returns {TODO} returns the callback function with results
+ */
+ buildModule(module, optional, origin, dependencies, thisCallback) {
+ let callbackList = this._buildingModules.get(module);
+ if (callbackList) {
+ callbackList.push(thisCallback);
+ return;
+ }
+ this._buildingModules.set(module, (callbackList = [thisCallback]));
+
+ const callback = err => {
+ this._buildingModules.delete(module);
+ for (const cb of callbackList) {
+ cb(err);
+ }
+ };
+
+ this.hooks.buildModule.call(module);
+ module.build(
+ this.options,
+ this,
+ this.resolverFactory.get("normal", module.resolveOptions),
+ this.inputFileSystem,
+ error => {
+ const errors = module.errors;
+ for (let indexError = 0; indexError < errors.length; indexError++) {
+ const err = errors[indexError];
+ err.origin = origin;
+ err.dependencies = dependencies;
+ if (optional) {
+ this.warnings.push(err);
+ } else {
+ this.errors.push(err);
+ }
+ }
+
+ const warnings = module.warnings;
+ for (
+ let indexWarning = 0;
+ indexWarning < warnings.length;
+ indexWarning++
+ ) {
+ const war = warnings[indexWarning];
+ war.origin = origin;
+ war.dependencies = dependencies;
+ this.warnings.push(war);
+ }
+ const originalMap = module.dependencies.reduce((map, v, i) => {
+ map.set(v, i);
+ return map;
+ }, new Map());
+ module.dependencies.sort((a, b) => {
+ const cmp = compareLocations(a.loc, b.loc);
+ if (cmp) return cmp;
+ return originalMap.get(a) - originalMap.get(b);
+ });
+ if (error) {
+ this.hooks.failedModule.call(module, error);
+ return callback(error);
+ }
+ this.hooks.succeedModule.call(module);
+ return callback();
+ }
+ );
+ }
+
+ /**
+ * @param {Module} module to be processed for deps
+ * @param {ModuleCallback} callback callback to be triggered
+ * @returns {void}
+ */
+ processModuleDependencies(module, callback) {
+ const dependencies = new Map();
+
+ const addDependency = dep => {
+ const resourceIdent = dep.getResourceIdentifier();
+ if (resourceIdent) {
+ const factory = this.dependencyFactories.get(dep.constructor);
+ if (factory === undefined) {
+ throw new Error(
+ `No module factory available for dependency type: ${dep.constructor.name}`
+ );
+ }
+ let innerMap = dependencies.get(factory);
+ if (innerMap === undefined) {
+ dependencies.set(factory, (innerMap = new Map()));
+ }
+ let list = innerMap.get(resourceIdent);
+ if (list === undefined) innerMap.set(resourceIdent, (list = []));
+ list.push(dep);
+ }
+ };
+
+ const addDependenciesBlock = block => {
+ if (block.dependencies) {
+ iterationOfArrayCallback(block.dependencies, addDependency);
+ }
+ if (block.blocks) {
+ iterationOfArrayCallback(block.blocks, addDependenciesBlock);
+ }
+ if (block.variables) {
+ iterationBlockVariable(block.variables, addDependency);
+ }
+ };
+
+ try {
+ addDependenciesBlock(module);
+ } catch (e) {
+ callback(e);
+ }
+
+ const sortedDependencies = [];
+
+ for (const pair1 of dependencies) {
+ for (const pair2 of pair1[1]) {
+ sortedDependencies.push({
+ factory: pair1[0],
+ dependencies: pair2[1]
+ });
+ }
+ }
+
+ this.addModuleDependencies(
+ module,
+ sortedDependencies,
+ this.bail,
+ null,
+ true,
+ callback
+ );
+ }
+
+ /**
+ * @param {Module} module module to add deps to
+ * @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through
+ * @param {(boolean|null)=} bail whether to bail or not
+ * @param {TODO} cacheGroup optional cacheGroup
+ * @param {boolean} recursive whether it is recursive traversal
+ * @param {function} callback callback for when dependencies are finished being added
+ * @returns {void}
+ */
+ addModuleDependencies(
+ module,
+ dependencies,
+ bail,
+ cacheGroup,
+ recursive,
+ callback
+ ) {
+ const start = this.profile && Date.now();
+ const currentProfile = this.profile && {};
+
+ asyncLib.forEach(
+ dependencies,
+ (item, callback) => {
+ const dependencies = item.dependencies;
+
+ const errorAndCallback = err => {
+ err.origin = module;
+ err.dependencies = dependencies;
+ this.errors.push(err);
+ if (bail) {
+ callback(err);
+ } else {
+ callback();
+ }
+ };
+ const warningAndCallback = err => {
+ err.origin = module;
+ this.warnings.push(err);
+ callback();
+ };
+
+ const semaphore = this.semaphore;
+ semaphore.acquire(() => {
+ const factory = item.factory;
+ factory.create(
+ {
+ contextInfo: {
+ issuer: module.nameForCondition && module.nameForCondition(),
+ compiler: this.compiler.name
+ },
+ resolveOptions: module.resolveOptions,
+ context: module.context,
+ dependencies: dependencies
+ },
+ (err, dependentModule) => {
+ let afterFactory;
+
+ const isOptional = () => {
+ return dependencies.every(d => d.optional);
+ };
+
+ const errorOrWarningAndCallback = err => {
+ if (isOptional()) {
+ return warningAndCallback(err);
+ } else {
+ return errorAndCallback(err);
+ }
+ };
+
+ if (err) {
+ semaphore.release();
+ return errorOrWarningAndCallback(
+ new ModuleNotFoundError(module, err)
+ );
+ }
+ if (!dependentModule) {
+ semaphore.release();
+ return process.nextTick(callback);
+ }
+ if (currentProfile) {
+ afterFactory = Date.now();
+ currentProfile.factory = afterFactory - start;
+ }
+
+ const iterationDependencies = depend => {
+ for (let index = 0; index < depend.length; index++) {
+ const dep = depend[index];
+ dep.module = dependentModule;
+ dependentModule.addReason(module, dep);
+ }
+ };
+
+ const addModuleResult = this.addModule(
+ dependentModule,
+ cacheGroup
+ );
+ dependentModule = addModuleResult.module;
+ iterationDependencies(dependencies);
+
+ const afterBuild = () => {
+ if (recursive && addModuleResult.dependencies) {
+ this.processModuleDependencies(dependentModule, callback);
+ } else {
+ return callback();
+ }
+ };
+
+ if (addModuleResult.issuer) {
+ if (currentProfile) {
+ dependentModule.profile = currentProfile;
+ }
+
+ dependentModule.issuer = module;
+ } else {
+ if (this.profile) {
+ if (module.profile) {
+ const time = Date.now() - start;
+ if (
+ !module.profile.dependencies ||
+ time > module.profile.dependencies
+ ) {
+ module.profile.dependencies = time;
+ }
+ }
+ }
+ }
+
+ if (addModuleResult.build) {
+ this.buildModule(
+ dependentModule,
+ isOptional(),
+ module,
+ dependencies,
+ err => {
+ if (err) {
+ semaphore.release();
+ return errorOrWarningAndCallback(err);
+ }
+
+ if (currentProfile) {
+ const afterBuilding = Date.now();
+ currentProfile.building = afterBuilding - afterFactory;
+ }
+
+ semaphore.release();
+ afterBuild();
+ }
+ );
+ } else {
+ semaphore.release();
+ this.waitForBuildingFinished(dependentModule, afterBuild);
+ }
+ }
+ );
+ });
+ },
+ err => {
+ // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
+ // errors are created inside closures that keep a reference to the Compilation, so errors are
+ // leaking the Compilation object.
+
+ if (err) {
+ // eslint-disable-next-line no-self-assign
+ err.stack = err.stack;
+ return callback(err);
+ }
+
+ return process.nextTick(callback);
+ }
+ );
+ }
+
+ /**
+ *
+ * @param {string} context context string path
+ * @param {Dependency} dependency dependency used to create Module chain
+ * @param {OnModuleCallback} onModule function invoked on modules creation
+ * @param {ModuleChainCallback} callback callback for when module chain is complete
+ * @returns {void} will throw if dependency instance is not a valid Dependency
+ */
+ _addModuleChain(context, dependency, onModule, callback) {
+ const start = this.profile && Date.now();
+ const currentProfile = this.profile && {};
+
+ const errorAndCallback = this.bail
+ ? err => {
+ callback(err);
+ }
+ : err => {
+ err.dependencies = [dependency];
+ this.errors.push(err);
+ callback();
+ };
+
+ if (
+ typeof dependency !== "object" ||
+ dependency === null ||
+ !dependency.constructor
+ ) {
+ throw new Error("Parameter 'dependency' must be a Dependency");
+ }
+ const Dep = /** @type {DepConstructor} */ (dependency.constructor);
+ const moduleFactory = this.dependencyFactories.get(Dep);
+ if (!moduleFactory) {
+ throw new Error(
+ `No dependency factory available for this dependency type: ${dependency.constructor.name}`
+ );
+ }
+
+ this.semaphore.acquire(() => {
+ moduleFactory.create(
+ {
+ contextInfo: {
+ issuer: "",
+ compiler: this.compiler.name
+ },
+ context: context,
+ dependencies: [dependency]
+ },
+ (err, module) => {
+ if (err) {
+ this.semaphore.release();
+ return errorAndCallback(new EntryModuleNotFoundError(err));
+ }
+
+ let afterFactory;
+
+ if (currentProfile) {
+ afterFactory = Date.now();
+ currentProfile.factory = afterFactory - start;
+ }
+
+ const addModuleResult = this.addModule(module);
+ module = addModuleResult.module;
+
+ onModule(module);
+
+ dependency.module = module;
+ module.addReason(null, dependency);
+
+ const afterBuild = () => {
+ if (addModuleResult.dependencies) {
+ this.processModuleDependencies(module, err => {
+ if (err) return callback(err);
+ callback(null, module);
+ });
+ } else {
+ return callback(null, module);
+ }
+ };
+
+ if (addModuleResult.issuer) {
+ if (currentProfile) {
+ module.profile = currentProfile;
+ }
+ }
+
+ if (addModuleResult.build) {
+ this.buildModule(module, false, null, null, err => {
+ if (err) {
+ this.semaphore.release();
+ return errorAndCallback(err);
+ }
+
+ if (currentProfile) {
+ const afterBuilding = Date.now();
+ currentProfile.building = afterBuilding - afterFactory;
+ }
+
+ this.semaphore.release();
+ afterBuild();
+ });
+ } else {
+ this.semaphore.release();
+ this.waitForBuildingFinished(module, afterBuild);
+ }
+ }
+ );
+ });
+ }
+
+ /**
+ *
+ * @param {string} context context path for entry
+ * @param {Dependency} entry entry dependency being created
+ * @param {string} name name of entry
+ * @param {ModuleCallback} callback callback function
+ * @returns {void} returns
+ */
+ addEntry(context, entry, name, callback) {
+ this.hooks.addEntry.call(entry, name);
+
+ const slot = {
+ name: name,
+ // TODO webpack 5 remove `request`
+ request: null,
+ module: null
+ };
+
+ if (entry instanceof ModuleDependency) {
+ slot.request = entry.request;
+ }
+
+ // TODO webpack 5: merge modules instead when multiple entry modules are supported
+ const idx = this._preparedEntrypoints.findIndex(slot => slot.name === name);
+ if (idx >= 0) {
+ // Overwrite existing entrypoint
+ this._preparedEntrypoints[idx] = slot;
+ } else {
+ this._preparedEntrypoints.push(slot);
+ }
+ this._addModuleChain(
+ context,
+ entry,
+ module => {
+ this.entries.push(module);
+ },
+ (err, module) => {
+ if (err) {
+ this.hooks.failedEntry.call(entry, name, err);
+ return callback(err);
+ }
+
+ if (module) {
+ slot.module = module;
+ } else {
+ const idx = this._preparedEntrypoints.indexOf(slot);
+ if (idx >= 0) {
+ this._preparedEntrypoints.splice(idx, 1);
+ }
+ }
+ this.hooks.succeedEntry.call(entry, name, module);
+ return callback(null, module);
+ }
+ );
+ }
+
+ /**
+ * @param {string} context context path string
+ * @param {Dependency} dependency dep used to create module
+ * @param {ModuleCallback} callback module callback sending module up a level
+ * @returns {void}
+ */
+ prefetch(context, dependency, callback) {
+ this._addModuleChain(
+ context,
+ dependency,
+ module => {
+ module.prefetched = true;
+ },
+ callback
+ );
+ }
+
+ /**
+ * @param {Module} module module to be rebuilt
+ * @param {Callback} thisCallback callback when module finishes rebuilding
+ * @returns {void}
+ */
+ rebuildModule(module, thisCallback) {
+ let callbackList = this._rebuildingModules.get(module);
+ if (callbackList) {
+ callbackList.push(thisCallback);
+ return;
+ }
+ this._rebuildingModules.set(module, (callbackList = [thisCallback]));
+
+ const callback = err => {
+ this._rebuildingModules.delete(module);
+ for (const cb of callbackList) {
+ cb(err);
+ }
+ };
+
+ this.hooks.rebuildModule.call(module);
+ const oldDependencies = module.dependencies.slice();
+ const oldVariables = module.variables.slice();
+ const oldBlocks = module.blocks.slice();
+ module.unbuild();
+ this.buildModule(module, false, module, null, err => {
+ if (err) {
+ this.hooks.finishRebuildingModule.call(module);
+ return callback(err);
+ }
+
+ this.processModuleDependencies(module, err => {
+ if (err) return callback(err);
+ this.removeReasonsOfDependencyBlock(module, {
+ dependencies: oldDependencies,
+ variables: oldVariables,
+ blocks: oldBlocks
+ });
+ this.hooks.finishRebuildingModule.call(module);
+ callback();
+ });
+ });
+ }
+
+ finish(callback) {
+ const modules = this.modules;
+ this.hooks.finishModules.callAsync(modules, err => {
+ if (err) return callback(err);
+
+ for (let index = 0; index < modules.length; index++) {
+ const module = modules[index];
+ this.reportDependencyErrorsAndWarnings(module, [module]);
+ }
+
+ callback();
+ });
+ }
+
+ unseal() {
+ this.hooks.unseal.call();
+ this.chunks.length = 0;
+ this.chunkGroups.length = 0;
+ this.namedChunks.clear();
+ this.namedChunkGroups.clear();
+ this.additionalChunkAssets.length = 0;
+ this.assets = {};
+ this.assetsInfo.clear();
+ for (const module of this.modules) {
+ module.unseal();
+ }
+ }
+
+ /**
+ * @param {Callback} callback signals when the seal method is finishes
+ * @returns {void}
+ */
+ seal(callback) {
+ this.hooks.seal.call();
+
+ while (
+ this.hooks.optimizeDependenciesBasic.call(this.modules) ||
+ this.hooks.optimizeDependencies.call(this.modules) ||
+ this.hooks.optimizeDependenciesAdvanced.call(this.modules)
+ ) {
+ /* empty */
+ }
+ this.hooks.afterOptimizeDependencies.call(this.modules);
+
+ this.hooks.beforeChunks.call();
+ for (const preparedEntrypoint of this._preparedEntrypoints) {
+ const module = preparedEntrypoint.module;
+ const name = preparedEntrypoint.name;
+ const chunk = this.addChunk(name);
+ const entrypoint = new Entrypoint(name);
+ entrypoint.setRuntimeChunk(chunk);
+ entrypoint.addOrigin(null, name, preparedEntrypoint.request);
+ this.namedChunkGroups.set(name, entrypoint);
+ this.entrypoints.set(name, entrypoint);
+ this.chunkGroups.push(entrypoint);
+
+ GraphHelpers.connectChunkGroupAndChunk(entrypoint, chunk);
+ GraphHelpers.connectChunkAndModule(chunk, module);
+
+ chunk.entryModule = module;
+ chunk.name = name;
+
+ this.assignDepth(module);
+ }
+ buildChunkGraph(
+ this,
+ /** @type {Entrypoint[]} */ (this.chunkGroups.slice())
+ );
+ this.sortModules(this.modules);
+ this.hooks.afterChunks.call(this.chunks);
+
+ this.hooks.optimize.call();
+
+ while (
+ this.hooks.optimizeModulesBasic.call(this.modules) ||
+ this.hooks.optimizeModules.call(this.modules) ||
+ this.hooks.optimizeModulesAdvanced.call(this.modules)
+ ) {
+ /* empty */
+ }
+ this.hooks.afterOptimizeModules.call(this.modules);
+
+ while (
+ this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) ||
+ this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) ||
+ this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)
+ ) {
+ /* empty */
+ }
+ this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
+
+ this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
+ if (err) {
+ return callback(err);
+ }
+
+ this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
+
+ while (
+ this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) ||
+ this.hooks.optimizeChunkModules.call(this.chunks, this.modules) ||
+ this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules)
+ ) {
+ /* empty */
+ }
+ this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
+
+ const shouldRecord = this.hooks.shouldRecord.call() !== false;
+
+ this.hooks.reviveModules.call(this.modules, this.records);
+ this.hooks.optimizeModuleOrder.call(this.modules);
+ this.hooks.advancedOptimizeModuleOrder.call(this.modules);
+ this.hooks.beforeModuleIds.call(this.modules);
+ this.hooks.moduleIds.call(this.modules);
+ this.applyModuleIds();
+ this.hooks.optimizeModuleIds.call(this.modules);
+ this.hooks.afterOptimizeModuleIds.call(this.modules);
+
+ this.sortItemsWithModuleIds();
+
+ this.hooks.reviveChunks.call(this.chunks, this.records);
+ this.hooks.optimizeChunkOrder.call(this.chunks);
+ this.hooks.beforeChunkIds.call(this.chunks);
+ this.applyChunkIds();
+ this.hooks.optimizeChunkIds.call(this.chunks);
+ this.hooks.afterOptimizeChunkIds.call(this.chunks);
+
+ this.sortItemsWithChunkIds();
+
+ if (shouldRecord) {
+ this.hooks.recordModules.call(this.modules, this.records);
+ this.hooks.recordChunks.call(this.chunks, this.records);
+ }
+
+ this.hooks.beforeHash.call();
+ this.createHash();
+ this.hooks.afterHash.call();
+
+ if (shouldRecord) {
+ this.hooks.recordHash.call(this.records);
+ }
+
+ this.hooks.beforeModuleAssets.call();
+ this.createModuleAssets();
+ if (this.hooks.shouldGenerateChunkAssets.call() !== false) {
+ this.hooks.beforeChunkAssets.call();
+ this.createChunkAssets();
+ }
+ this.hooks.additionalChunkAssets.call(this.chunks);
+ this.summarizeDependencies();
+ if (shouldRecord) {
+ this.hooks.record.call(this, this.records);
+ }
+
+ this.hooks.additionalAssets.callAsync(err => {
+ if (err) {
+ return callback(err);
+ }
+ this.hooks.optimizeChunkAssets.callAsync(this.chunks, err => {
+ if (err) {
+ return callback(err);
+ }
+ this.hooks.afterOptimizeChunkAssets.call(this.chunks);
+ this.hooks.optimizeAssets.callAsync(this.assets, err => {
+ if (err) {
+ return callback(err);
+ }
+ this.hooks.afterOptimizeAssets.call(this.assets);
+ if (this.hooks.needAdditionalSeal.call()) {
+ this.unseal();
+ return this.seal(callback);
+ }
+ return this.hooks.afterSeal.callAsync(callback);
+ });
+ });
+ });
+ });
+ }
+
+ /**
+ * @param {Module[]} modules the modules array on compilation to perform the sort for
+ * @returns {void}
+ */
+ sortModules(modules) {
+ // TODO webpack 5: this should only be enabled when `moduleIds: "natural"`
+ // TODO move it into a plugin (NaturalModuleIdsPlugin) and use this in WebpackOptionsApply
+ // TODO remove this method
+ modules.sort(byIndexOrIdentifier);
+ }
+
+ /**
+ * @param {Module} module moulde to report from
+ * @param {DependenciesBlock[]} blocks blocks to report from
+ * @returns {void}
+ */
+ reportDependencyErrorsAndWarnings(module, blocks) {
+ for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
+ const block = blocks[indexBlock];
+ const dependencies = block.dependencies;
+
+ for (let indexDep = 0; indexDep < dependencies.length; indexDep++) {
+ const d = dependencies[indexDep];
+
+ const warnings = d.getWarnings();
+ if (warnings) {
+ for (let indexWar = 0; indexWar < warnings.length; indexWar++) {
+ const w = warnings[indexWar];
+
+ const warning = new ModuleDependencyWarning(module, w, d.loc);
+ this.warnings.push(warning);
+ }
+ }
+ const errors = d.getErrors();
+ if (errors) {
+ for (let indexErr = 0; indexErr < errors.length; indexErr++) {
+ const e = errors[indexErr];
+
+ const error = new ModuleDependencyError(module, e, d.loc);
+ this.errors.push(error);
+ }
+ }
+ }
+
+ this.reportDependencyErrorsAndWarnings(module, block.blocks);
+ }
+ }
+
+ /**
+ * @param {TODO} groupOptions options for the chunk group
+ * @param {Module} module the module the references the chunk group
+ * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
+ * @param {string} request the request from which the the chunk group is referenced
+ * @returns {ChunkGroup} the new or existing chunk group
+ */
+ addChunkInGroup(groupOptions, module, loc, request) {
+ if (typeof groupOptions === "string") {
+ groupOptions = { name: groupOptions };
+ }
+ const name = groupOptions.name;
+ if (name) {
+ const chunkGroup = this.namedChunkGroups.get(name);
+ if (chunkGroup !== undefined) {
+ chunkGroup.addOptions(groupOptions);
+ if (module) {
+ chunkGroup.addOrigin(module, loc, request);
+ }
+ return chunkGroup;
+ }
+ }
+ const chunkGroup = new ChunkGroup(groupOptions);
+ if (module) chunkGroup.addOrigin(module, loc, request);
+ const chunk = this.addChunk(name);
+
+ GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk);
+
+ this.chunkGroups.push(chunkGroup);
+ if (name) {
+ this.namedChunkGroups.set(name, chunkGroup);
+ }
+ return chunkGroup;
+ }
+
+ /**
+ * This method first looks to see if a name is provided for a new chunk,
+ * and first looks to see if any named chunks already exist and reuse that chunk instead.
+ *
+ * @param {string=} name optional chunk name to be provided
+ * @returns {Chunk} create a chunk (invoked during seal event)
+ */
+ addChunk(name) {
+ if (name) {
+ const chunk = this.namedChunks.get(name);
+ if (chunk !== undefined) {
+ return chunk;
+ }
+ }
+ const chunk = new Chunk(name);
+ this.chunks.push(chunk);
+ if (name) {
+ this.namedChunks.set(name, chunk);
+ }
+ return chunk;
+ }
+
+ /**
+ * @param {Module} module module to assign depth
+ * @returns {void}
+ */
+ assignDepth(module) {
+ const queue = new Set([module]);
+ let depth;
+
+ module.depth = 0;
+
+ /**
+ * @param {Module} module module for processeing
+ * @returns {void}
+ */
+ const enqueueJob = module => {
+ const d = module.depth;
+ if (typeof d === "number" && d <= depth) return;
+ queue.add(module);
+ module.depth = depth;
+ };
+
+ /**
+ * @param {Dependency} dependency dependency to assign depth to
+ * @returns {void}
+ */
+ const assignDepthToDependency = dependency => {
+ if (dependency.module) {
+ enqueueJob(dependency.module);
+ }
+ };
+
+ /**
+ * @param {DependenciesBlock} block block to assign depth to
+ * @returns {void}
+ */
+ const assignDepthToDependencyBlock = block => {
+ if (block.variables) {
+ iterationBlockVariable(block.variables, assignDepthToDependency);
+ }
+
+ if (block.dependencies) {
+ iterationOfArrayCallback(block.dependencies, assignDepthToDependency);
+ }
+
+ if (block.blocks) {
+ iterationOfArrayCallback(block.blocks, assignDepthToDependencyBlock);
+ }
+ };
+
+ for (module of queue) {
+ queue.delete(module);
+ depth = module.depth;
+
+ depth++;
+ assignDepthToDependencyBlock(module);
+ }
+ }
+
+ /**
+ * @param {Module} module the module containing the dependency
+ * @param {Dependency} dependency the dependency
+ * @returns {DependencyReference} a reference for the dependency
+ */
+ getDependencyReference(module, dependency) {
+ // TODO remove dep.getReference existence check in webpack 5
+ if (typeof dependency.getReference !== "function") return null;
+ const ref = dependency.getReference();
+ if (!ref) return null;
+ return this.hooks.dependencyReference.call(ref, dependency, module);
+ }
+
+ /**
+ *
+ * @param {Module} module module relationship for removal
+ * @param {DependenciesBlockLike} block //TODO: good description
+ * @returns {void}
+ */
+ removeReasonsOfDependencyBlock(module, block) {
+ const iteratorDependency = d => {
+ if (!d.module) {
+ return;
+ }
+ if (d.module.removeReason(module, d)) {
+ for (const chunk of d.module.chunksIterable) {
+ this.patchChunksAfterReasonRemoval(d.module, chunk);
+ }
+ }
+ };
+
+ if (block.blocks) {
+ iterationOfArrayCallback(block.blocks, block =>
+ this.removeReasonsOfDependencyBlock(module, block)
+ );
+ }
+
+ if (block.dependencies) {
+ iterationOfArrayCallback(block.dependencies, iteratorDependency);
+ }
+
+ if (block.variables) {
+ iterationBlockVariable(block.variables, iteratorDependency);
+ }
+ }
+
+ /**
+ * @param {Module} module module to patch tie
+ * @param {Chunk} chunk chunk to patch tie
+ * @returns {void}
+ */
+ patchChunksAfterReasonRemoval(module, chunk) {
+ if (!module.hasReasons()) {
+ this.removeReasonsOfDependencyBlock(module, module);
+ }
+ if (!module.hasReasonForChunk(chunk)) {
+ if (module.removeChunk(chunk)) {
+ this.removeChunkFromDependencies(module, chunk);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param {DependenciesBlock} block block tie for Chunk
+ * @param {Chunk} chunk chunk to remove from dep
+ * @returns {void}
+ */
+ removeChunkFromDependencies(block, chunk) {
+ const iteratorDependency = d => {
+ if (!d.module) {
+ return;
+ }
+ this.patchChunksAfterReasonRemoval(d.module, chunk);
+ };
+
+ const blocks = block.blocks;
+ for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
+ const asyncBlock = blocks[indexBlock];
+ // Grab all chunks from the first Block's AsyncDepBlock
+ const chunks = asyncBlock.chunkGroup.chunks;
+ // For each chunk in chunkGroup
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ const iteratedChunk = chunks[indexChunk];
+ asyncBlock.chunkGroup.removeChunk(iteratedChunk);
+ asyncBlock.chunkGroup.removeParent(iteratedChunk);
+ // Recurse
+ this.removeChunkFromDependencies(block, iteratedChunk);
+ }
+ }
+
+ if (block.dependencies) {
+ iterationOfArrayCallback(block.dependencies, iteratorDependency);
+ }
+
+ if (block.variables) {
+ iterationBlockVariable(block.variables, iteratorDependency);
+ }
+ }
+
+ applyModuleIds() {
+ const unusedIds = [];
+ let nextFreeModuleId = 0;
+ const usedIds = new Set();
+ if (this.usedModuleIds) {
+ for (const id of this.usedModuleIds) {
+ usedIds.add(id);
+ }
+ }
+
+ const modules1 = this.modules;
+ for (let indexModule1 = 0; indexModule1 < modules1.length; indexModule1++) {
+ const module1 = modules1[indexModule1];
+ if (module1.id !== null) {
+ usedIds.add(module1.id);
+ }
+ }
+
+ if (usedIds.size > 0) {
+ let usedIdMax = -1;
+ for (const usedIdKey of usedIds) {
+ if (typeof usedIdKey !== "number") {
+ continue;
+ }
+
+ usedIdMax = Math.max(usedIdMax, usedIdKey);
+ }
+
+ let lengthFreeModules = (nextFreeModuleId = usedIdMax + 1);
+
+ while (lengthFreeModules--) {
+ if (!usedIds.has(lengthFreeModules)) {
+ unusedIds.push(lengthFreeModules);
+ }
+ }
+ }
+
+ const modules2 = this.modules;
+ for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
+ const module2 = modules2[indexModule2];
+ if (module2.id === null) {
+ if (unusedIds.length > 0) {
+ module2.id = unusedIds.pop();
+ } else {
+ module2.id = nextFreeModuleId++;
+ }
+ }
+ }
+ }
+
+ applyChunkIds() {
+ /** @type {Set<number>} */
+ const usedIds = new Set();
+
+ // Get used ids from usedChunkIds property (i. e. from records)
+ if (this.usedChunkIds) {
+ for (const id of this.usedChunkIds) {
+ if (typeof id !== "number") {
+ continue;
+ }
+
+ usedIds.add(id);
+ }
+ }
+
+ // Get used ids from existing chunks
+ const chunks = this.chunks;
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ const chunk = chunks[indexChunk];
+ const usedIdValue = chunk.id;
+
+ if (typeof usedIdValue !== "number") {
+ continue;
+ }
+
+ usedIds.add(usedIdValue);
+ }
+
+ // Calculate maximum assigned chunk id
+ let nextFreeChunkId = -1;
+ for (const id of usedIds) {
+ nextFreeChunkId = Math.max(nextFreeChunkId, id);
+ }
+ nextFreeChunkId++;
+
+ // Determine free chunk ids from 0 to maximum
+ /** @type {number[]} */
+ const unusedIds = [];
+ if (nextFreeChunkId > 0) {
+ let index = nextFreeChunkId;
+ while (index--) {
+ if (!usedIds.has(index)) {
+ unusedIds.push(index);
+ }
+ }
+ }
+
+ // Assign ids to chunk which has no id
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ const chunk = chunks[indexChunk];
+ if (chunk.id === null) {
+ if (unusedIds.length > 0) {
+ chunk.id = unusedIds.pop();
+ } else {
+ chunk.id = nextFreeChunkId++;
+ }
+ }
+ if (!chunk.ids) {
+ chunk.ids = [chunk.id];
+ }
+ }
+ }
+
+ sortItemsWithModuleIds() {
+ this.modules.sort(byIdOrIdentifier);
+
+ const modules = this.modules;
+ for (let indexModule = 0; indexModule < modules.length; indexModule++) {
+ modules[indexModule].sortItems(false);
+ }
+
+ const chunks = this.chunks;
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ chunks[indexChunk].sortItems();
+ }
+
+ chunks.sort((a, b) => a.compareTo(b));
+ }
+
+ sortItemsWithChunkIds() {
+ for (const chunkGroup of this.chunkGroups) {
+ chunkGroup.sortItems();
+ }
+
+ this.chunks.sort(byId);
+
+ for (
+ let indexModule = 0;
+ indexModule < this.modules.length;
+ indexModule++
+ ) {
+ this.modules[indexModule].sortItems(true);
+ }
+
+ const chunks = this.chunks;
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ chunks[indexChunk].sortItems();
+ }
+
+ /**
+ * Used to sort errors and warnings in compilation. this.warnings, and
+ * this.errors contribute to the compilation hash and therefore should be
+ * updated whenever other references (having a chunk id) are sorted. This preserves the hash
+ * integrity
+ *
+ * @param {WebpackError} a first WebpackError instance (including subclasses)
+ * @param {WebpackError} b second WebpackError instance (including subclasses)
+ * @returns {-1|0|1} sort order index
+ */
+ const byMessage = (a, b) => {
+ const ma = `${a.message}`;
+ const mb = `${b.message}`;
+ if (ma < mb) return -1;
+ if (mb < ma) return 1;
+ return 0;
+ };
+
+ this.errors.sort(byMessage);
+ this.warnings.sort(byMessage);
+ this.children.sort(byNameOrHash);
+ }
+
+ summarizeDependencies() {
+ this.fileDependencies = new SortableSet(this.compilationDependencies);
+ this.contextDependencies = new SortableSet();
+ this.missingDependencies = new SortableSet();
+
+ for (
+ let indexChildren = 0;
+ indexChildren < this.children.length;
+ indexChildren++
+ ) {
+ const child = this.children[indexChildren];
+
+ addAllToSet(this.fileDependencies, child.fileDependencies);
+ addAllToSet(this.contextDependencies, child.contextDependencies);
+ addAllToSet(this.missingDependencies, child.missingDependencies);
+ }
+
+ for (
+ let indexModule = 0;
+ indexModule < this.modules.length;
+ indexModule++
+ ) {
+ const module = this.modules[indexModule];
+
+ if (module.buildInfo.fileDependencies) {
+ addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies);
+ }
+ if (module.buildInfo.contextDependencies) {
+ addAllToSet(
+ this.contextDependencies,
+ module.buildInfo.contextDependencies
+ );
+ }
+ }
+ for (const error of this.errors) {
+ if (
+ typeof error.missing === "object" &&
+ error.missing &&
+ error.missing[Symbol.iterator]
+ ) {
+ addAllToSet(this.missingDependencies, error.missing);
+ }
+ }
+ this.fileDependencies.sort();
+ this.contextDependencies.sort();
+ this.missingDependencies.sort();
+ }
+
+ createHash() {
+ const outputOptions = this.outputOptions;
+ const hashFunction = outputOptions.hashFunction;
+ const hashDigest = outputOptions.hashDigest;
+ const hashDigestLength = outputOptions.hashDigestLength;
+ const hash = createHash(hashFunction);
+ if (outputOptions.hashSalt) {
+ hash.update(outputOptions.hashSalt);
+ }
+ this.mainTemplate.updateHash(hash);
+ this.chunkTemplate.updateHash(hash);
+ for (const key of Object.keys(this.moduleTemplates).sort()) {
+ this.moduleTemplates[key].updateHash(hash);
+ }
+ for (const child of this.children) {
+ hash.update(child.hash);
+ }
+ for (const warning of this.warnings) {
+ hash.update(`${warning.message}`);
+ }
+ for (const error of this.errors) {
+ hash.update(`${error.message}`);
+ }
+ const modules = this.modules;
+ for (let i = 0; i < modules.length; i++) {
+ const module = modules[i];
+ const moduleHash = createHash(hashFunction);
+ module.updateHash(moduleHash);
+ module.hash = /** @type {string} */ (moduleHash.digest(hashDigest));
+ module.renderedHash = module.hash.substr(0, hashDigestLength);
+ }
+ // clone needed as sort below is inplace mutation
+ const chunks = this.chunks.slice();
+ /**
+ * sort here will bring all "falsy" values to the beginning
+ * this is needed as the "hasRuntime()" chunks are dependent on the
+ * hashes of the non-runtime chunks.
+ */
+ chunks.sort((a, b) => {
+ const aEntry = a.hasRuntime();
+ const bEntry = b.hasRuntime();
+ if (aEntry && !bEntry) return 1;
+ if (!aEntry && bEntry) return -1;
+ return byId(a, b);
+ });
+ for (let i = 0; i < chunks.length; i++) {
+ const chunk = chunks[i];
+ const chunkHash = createHash(hashFunction);
+ try {
+ if (outputOptions.hashSalt) {
+ chunkHash.update(outputOptions.hashSalt);
+ }
+ chunk.updateHash(chunkHash);
+ const template = chunk.hasRuntime()
+ ? this.mainTemplate
+ : this.chunkTemplate;
+ template.updateHashForChunk(
+ chunkHash,
+ chunk,
+ this.moduleTemplates.javascript,
+ this.dependencyTemplates
+ );
+ this.hooks.chunkHash.call(chunk, chunkHash);
+ chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest));
+ hash.update(chunk.hash);
+ chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
+ this.hooks.contentHash.call(chunk);
+ } catch (err) {
+ this.errors.push(new ChunkRenderError(chunk, "", err));
+ }
+ }
+ this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
+ this.hash = this.fullHash.substr(0, hashDigestLength);
+ }
+
+ /**
+ * @param {string} update extra information
+ * @returns {void}
+ */
+ modifyHash(update) {
+ const outputOptions = this.outputOptions;
+ const hashFunction = outputOptions.hashFunction;
+ const hashDigest = outputOptions.hashDigest;
+ const hashDigestLength = outputOptions.hashDigestLength;
+ const hash = createHash(hashFunction);
+ hash.update(this.fullHash);
+ hash.update(update);
+ this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
+ this.hash = this.fullHash.substr(0, hashDigestLength);
+ }
+
+ /**
+ * @param {string} file file name
+ * @param {Source} source asset source
+ * @param {AssetInfo} assetInfo extra asset information
+ * @returns {void}
+ */
+ emitAsset(file, source, assetInfo = {}) {
+ if (this.assets[file]) {
+ if (!isSourceEqual(this.assets[file], source)) {
+ // TODO webpack 5: make this an error instead
+ this.warnings.push(
+ new WebpackError(
+ `Conflict: Multiple assets emit different content to the same filename ${file}`
+ )
+ );
+ this.assets[file] = source;
+ this.assetsInfo.set(file, assetInfo);
+ return;
+ }
+ const oldInfo = this.assetsInfo.get(file);
+ this.assetsInfo.set(file, Object.assign({}, oldInfo, assetInfo));
+ return;
+ }
+ this.assets[file] = source;
+ this.assetsInfo.set(file, assetInfo);
+ }
+
+ /**
+ * @param {string} file file name
+ * @param {Source | function(Source): Source} newSourceOrFunction new asset source or function converting old to new
+ * @param {AssetInfo | function(AssetInfo | undefined): AssetInfo} assetInfoUpdateOrFunction new asset info or function converting old to new
+ */
+ updateAsset(
+ file,
+ newSourceOrFunction,
+ assetInfoUpdateOrFunction = undefined
+ ) {
+ if (!this.assets[file]) {
+ throw new Error(
+ `Called Compilation.updateAsset for not existing filename ${file}`
+ );
+ }
+ if (typeof newSourceOrFunction === "function") {
+ this.assets[file] = newSourceOrFunction(this.assets[file]);
+ } else {
+ this.assets[file] = newSourceOrFunction;
+ }
+ if (assetInfoUpdateOrFunction !== undefined) {
+ const oldInfo = this.assetsInfo.get(file);
+ if (typeof assetInfoUpdateOrFunction === "function") {
+ this.assetsInfo.set(file, assetInfoUpdateOrFunction(oldInfo || {}));
+ } else {
+ this.assetsInfo.set(
+ file,
+ Object.assign({}, oldInfo, assetInfoUpdateOrFunction)
+ );
+ }
+ }
+ }
+
+ getAssets() {
+ /** @type {Asset[]} */
+ const array = [];
+ for (const assetName of Object.keys(this.assets)) {
+ if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) {
+ array.push({
+ name: assetName,
+ source: this.assets[assetName],
+ info: this.assetsInfo.get(assetName) || {}
+ });
+ }
+ }
+ return array;
+ }
+
+ /**
+ * @param {string} name the name of the asset
+ * @returns {Asset | undefined} the asset or undefined when not found
+ */
+ getAsset(name) {
+ if (!Object.prototype.hasOwnProperty.call(this.assets, name))
+ return undefined;
+ return {
+ name,
+ source: this.assets[name],
+ info: this.assetsInfo.get(name) || {}
+ };
+ }
+
+ createModuleAssets() {
+ for (let i = 0; i < this.modules.length; i++) {
+ const module = this.modules[i];
+ if (module.buildInfo.assets) {
+ const assetsInfo = module.buildInfo.assetsInfo;
+ for (const assetName of Object.keys(module.buildInfo.assets)) {
+ const fileName = this.getPath(assetName);
+ this.emitAsset(
+ fileName,
+ module.buildInfo.assets[assetName],
+ assetsInfo ? assetsInfo.get(assetName) : undefined
+ );
+ this.hooks.moduleAsset.call(module, fileName);
+ }
+ }
+ }
+ }
+
+ createChunkAssets() {
+ const outputOptions = this.outputOptions;
+ const cachedSourceMap = new Map();
+ /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
+ const alreadyWrittenFiles = new Map();
+ for (let i = 0; i < this.chunks.length; i++) {
+ const chunk = this.chunks[i];
+ chunk.files = [];
+ let source;
+ let file;
+ let filenameTemplate;
+ try {
+ const template = chunk.hasRuntime()
+ ? this.mainTemplate
+ : this.chunkTemplate;
+ const manifest = template.getRenderManifest({
+ chunk,
+ hash: this.hash,
+ fullHash: this.fullHash,
+ outputOptions,
+ moduleTemplates: this.moduleTemplates,
+ dependencyTemplates: this.dependencyTemplates
+ }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }]
+ for (const fileManifest of manifest) {
+ const cacheName = fileManifest.identifier;
+ const usedHash = fileManifest.hash;
+ filenameTemplate = fileManifest.filenameTemplate;
+ const pathAndInfo = this.getPathWithInfo(
+ filenameTemplate,
+ fileManifest.pathOptions
+ );
+ file = pathAndInfo.path;
+ const assetInfo = pathAndInfo.info;
+
+ // check if the same filename was already written by another chunk
+ const alreadyWritten = alreadyWrittenFiles.get(file);
+ if (alreadyWritten !== undefined) {
+ if (alreadyWritten.hash === usedHash) {
+ if (this.cache) {
+ this.cache[cacheName] = {
+ hash: usedHash,
+ source: alreadyWritten.source
+ };
+ }
+ chunk.files.push(file);
+ this.hooks.chunkAsset.call(chunk, file);
+ continue;
+ } else {
+ throw new Error(
+ `Conflict: Multiple chunks emit assets to the same filename ${file}` +
+ ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
+ );
+ }
+ }
+ if (
+ this.cache &&
+ this.cache[cacheName] &&
+ this.cache[cacheName].hash === usedHash
+ ) {
+ source = this.cache[cacheName].source;
+ } else {
+ source = fileManifest.render();
+ // Ensure that source is a cached source to avoid additional cost because of repeated access
+ if (!(source instanceof CachedSource)) {
+ const cacheEntry = cachedSourceMap.get(source);
+ if (cacheEntry) {
+ source = cacheEntry;
+ } else {
+ const cachedSource = new CachedSource(source);
+ cachedSourceMap.set(source, cachedSource);
+ source = cachedSource;
+ }
+ }
+ if (this.cache) {
+ this.cache[cacheName] = {
+ hash: usedHash,
+ source
+ };
+ }
+ }
+ this.emitAsset(file, source, assetInfo);
+ chunk.files.push(file);
+ this.hooks.chunkAsset.call(chunk, file);
+ alreadyWrittenFiles.set(file, {
+ hash: usedHash,
+ source,
+ chunk
+ });
+ }
+ } catch (err) {
+ this.errors.push(
+ new ChunkRenderError(chunk, file || filenameTemplate, err)
+ );
+ }
+ }
+ }
+
+ /**
+ * @param {string} filename used to get asset path with hash
+ * @param {TODO=} data // TODO: figure out this param type
+ * @returns {string} interpolated path
+ */
+ getPath(filename, data) {
+ data = data || {};
+ data.hash = data.hash || this.hash;
+ return this.mainTemplate.getAssetPath(filename, data);
+ }
+
+ /**
+ * @param {string} filename used to get asset path with hash
+ * @param {TODO=} data // TODO: figure out this param type
+ * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
+ */
+ getPathWithInfo(filename, data) {
+ data = data || {};
+ data.hash = data.hash || this.hash;
+ return this.mainTemplate.getAssetPathWithInfo(filename, data);
+ }
+
+ /**
+ * This function allows you to run another instance of webpack inside of webpack however as
+ * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
+ * from parent (or top level compiler) and creates a child Compilation
+ *
+ * @param {string} name name of the child compiler
+ * @param {TODO} outputOptions // Need to convert config schema to types for this
+ * @param {Plugin[]} plugins webpack plugins that will be applied
+ * @returns {Compiler} creates a child Compiler instance
+ */
+ createChildCompiler(name, outputOptions, plugins) {
+ const idx = this.childrenCounters[name] || 0;
+ this.childrenCounters[name] = idx + 1;
+ return this.compiler.createChildCompiler(
+ this,
+ name,
+ idx,
+ outputOptions,
+ plugins
+ );
+ }
+
+ checkConstraints() {
+ /** @type {Set<number|string>} */
+ const usedIds = new Set();
+
+ const modules = this.modules;
+ for (let indexModule = 0; indexModule < modules.length; indexModule++) {
+ const moduleId = modules[indexModule].id;
+ if (moduleId === null) continue;
+ if (usedIds.has(moduleId)) {
+ throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
+ }
+ usedIds.add(moduleId);
+ }
+
+ const chunks = this.chunks;
+ for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
+ const chunk = chunks[indexChunk];
+ if (chunks.indexOf(chunk) !== indexChunk) {
+ throw new Error(
+ `checkConstraints: duplicate chunk in compilation ${chunk.debugId}`
+ );
+ }
+ }
+
+ for (const chunkGroup of this.chunkGroups) {
+ chunkGroup.checkConstraints();
+ }
+ }
+}
+
+// TODO remove in webpack 5
+Compilation.prototype.applyPlugins = util.deprecate(
+ /**
+ * @deprecated
+ * @param {string} name Name
+ * @param {any[]} args Other arguments
+ * @returns {void}
+ * @this {Compilation}
+ */
+ function(name, ...args) {
+ this.hooks[
+ name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())
+ ].call(...args);
+ },
+ "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead"
+);
+
+// TODO remove in webpack 5
+Object.defineProperty(Compilation.prototype, "moduleTemplate", {
+ configurable: false,
+ get: util.deprecate(
+ /**
+ * @deprecated
+ * @this {Compilation}
+ * @returns {TODO} module template
+ */
+ function() {
+ return this.moduleTemplates.javascript;
+ },
+ "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead"
+ ),
+ set: util.deprecate(
+ /**
+ * @deprecated
+ * @param {ModuleTemplate} value Template value
+ * @this {Compilation}
+ * @returns {void}
+ */
+ function(value) {
+ this.moduleTemplates.javascript = value;
+ },
+ "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead."
+ )
+});
+
+module.exports = Compilation;