diff options
Diffstat (limited to 'node_modules/webpack/lib/Compilation.js')
-rw-r--r-- | node_modules/webpack/lib/Compilation.js | 2327 |
1 files changed, 0 insertions, 2327 deletions
diff --git a/node_modules/webpack/lib/Compilation.js b/node_modules/webpack/lib/Compilation.js deleted file mode 100644 index 6329174..0000000 --- a/node_modules/webpack/lib/Compilation.js +++ /dev/null @@ -1,2327 +0,0 @@ -/* - 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; |