<NME> Compilation.js <BEF> /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const asyncLib = require("neo-async"); const { HookMap, SyncHook, SyncBailHook, SyncWaterfallHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncParallelHook } = require("tapable"); const util = require("util"); const { CachedSource } = require("webpack-sources"); const { MultiItemCache } = require("./CacheFacade"); const Chunk = require("./Chunk"); const ChunkGraph = require("./ChunkGraph"); const ChunkGroup = require("./ChunkGroup"); const ChunkRenderError = require("./ChunkRenderError"); const ChunkTemplate = require("./ChunkTemplate"); const CodeGenerationError = require("./CodeGenerationError"); const CodeGenerationResults = require("./CodeGenerationResults"); const Dependency = require("./Dependency"); const DependencyTemplates = require("./DependencyTemplates"); const Entrypoint = require("./Entrypoint"); const ErrorHelpers = require("./ErrorHelpers"); const FileSystemInfo = require("./FileSystemInfo"); const { connectChunkGroupAndChunk, connectChunkGroupParentAndChild } = require("./GraphHelpers"); const { makeWebpackError, tryRunOrWebpackError } = require("./HookWebpackError"); const MainTemplate = require("./MainTemplate"); const Module = require("./Module"); const ModuleDependencyError = require("./ModuleDependencyError"); const ModuleDependencyWarning = require("./ModuleDependencyWarning"); const ModuleGraph = require("./ModuleGraph"); const ModuleHashingError = require("./ModuleHashingError"); const ModuleNotFoundError = require("./ModuleNotFoundError"); const ModuleProfile = require("./ModuleProfile"); const ModuleRestoreError = require("./ModuleRestoreError"); const ModuleStoreError = require("./ModuleStoreError"); const ModuleTemplate = require("./ModuleTemplate"); const RuntimeGlobals = require("./RuntimeGlobals"); const RuntimeTemplate = require("./RuntimeTemplate"); const Stats = require("./Stats"); const WebpackError = require("./WebpackError"); const buildChunkGraph = require("./buildChunkGraph"); const BuildCycleError = require("./errors/BuildCycleError"); const { Logger, LogType } = require("./logging/Logger"); const StatsFactory = require("./stats/StatsFactory"); const StatsPrinter = require("./stats/StatsPrinter"); const { equals: arrayEquals } = require("./util/ArrayHelpers"); const AsyncQueue = require("./util/AsyncQueue"); const LazySet = require("./util/LazySet"); const { provide } = require("./util/MapHelpers"); const WeakTupleMap = require("./util/WeakTupleMap"); const { cachedCleverMerge } = require("./util/cleverMerge"); const { compareLocations, concatComparators, compareSelect, compareIds, compareStringsNumeric, compareModulesByIdentifier } = require("./util/comparators"); const createHash = require("./util/createHash"); const { arrayToSetDeprecation, soonFrozenObjectDeprecation, createFakeHook } = require("./util/deprecation"); const processAsyncTree = require("./util/processAsyncTree"); const { getRuntimeKey } = require("./util/runtime"); const { isSourceEqual } = require("./util/source"); /** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */ /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescription */ /** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */ /** @typedef {import("../declarations/WebpackOptions").StatsOptions} StatsOptions */ /** @typedef {import("../declarations/WebpackOptions").WebpackPluginFunction} WebpackPluginFunction */ /** @typedef {import("../declarations/WebpackOptions").WebpackPluginInstance} WebpackPluginInstance */ /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ /** @typedef {import("./Cache")} Cache */ /** @typedef {import("./CacheFacade")} CacheFacade */ /** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */ /** @typedef {import("./Compiler")} Compiler */ /** @typedef {import("./Compiler").CompilationParams} CompilationParams */ /** @typedef {import("./DependenciesBlock")} DependenciesBlock */ /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ /** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */ /** @typedef {import("./DependencyTemplate")} DependencyTemplate */ /** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */ /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */ /** @typedef {import("./ModuleFactory")} ModuleFactory */ /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */ /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeModule")} RuntimeModule */ /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */ /** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions */ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsError} StatsError */ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModule} StatsModule */ /** @typedef {import("./util/Hash")} Hash */ /** @template T @typedef {import("./util/deprecation").FakeHook<T>} FakeHook<T> */ /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */ /** * @callback Callback * @param {(WebpackError | null)=} err * @returns {void} */ /** * @callback ModuleCallback * @param {(WebpackError | null)=} err * @param {Module=} result * @returns {void} */ /** * @callback ModuleFactoryResultCallback * @param {(WebpackError | null)=} err * @param {ModuleFactoryResult=} result * @returns {void} */ /** * @callback ModuleOrFactoryResultCallback * @param {(WebpackError | null)=} err * @param {Module | ModuleFactoryResult=} result * @returns {void} */ /** * @callback ExecuteModuleCallback * @param {(WebpackError | null)=} err * @param {ExecuteModuleResult=} result * @returns {void} */ /** * @typedef {Object} EntryData * @property {Dependency[]} dependencies dependencies of the entrypoint that should be evaluated at startup * @property {Dependency[]} includeDependencies dependencies of the entrypoint that should be included by not evaluated * @property {EntryOptions} options options of the entrypoint */ /** @typedef {new (...args: any[]) => Dependency} DepConstructor */ /** @typedef {Record<string, Source>} CompilationAssets */ /** * @typedef {Object} AvailableModulesChunkGroupMapping * @property {ChunkGroup} chunkGroup * @property {Set<Module>} availableModules * @property {boolean} needCopy */ /** * @typedef {Object} DependenciesBlockLike * @property {Dependency[]} dependencies * @property {AsyncDependenciesBlock[]} blocks */ /** * @typedef {Object} ChunkPathData * @property {string|number} id * @property {string=} name * @property {string} hash * @property {function(number): string=} hashWithLength * @property {(Record<string, string>)=} contentHash * @property {(Record<string, (length: number) => string>)=} contentHashWithLength */ /** * @typedef {Object} ChunkHashContext * @property {CodeGenerationResults} codeGenerationResults results of code generation * @property {RuntimeTemplate} runtimeTemplate the runtime template * @property {ModuleGraph} moduleGraph the module graph * @property {ChunkGraph} chunkGraph the chunk graph */ /** * @typedef {Object} RuntimeRequirementsContext * @property {ChunkGraph} chunkGraph the chunk graph * @property {CodeGenerationResults} codeGenerationResults the code generation results */ /** * @typedef {Object} ExecuteModuleOptions * @property {EntryOptions=} entryOptions */ /** * @typedef {Object} ExecuteModuleResult * @property {any} exports * @property {boolean} cacheable * @property {Map<string, { source: Source, info: AssetInfo }>} assets * @property {LazySet<string>} fileDependencies * @property {LazySet<string>} contextDependencies * @property {LazySet<string>} missingDependencies * @property {LazySet<string>} buildDependencies */ /** * @typedef {Object} ExecuteModuleArgument * @property {Module} module * @property {{ id: string, exports: any, loaded: boolean }=} moduleObject * @property {any} preparedInfo * @property {CodeGenerationResult} codeGenerationResult */ /** * @typedef {Object} ExecuteModuleContext * @property {Map<string, { source: Source, info: AssetInfo }>} assets * @property {Chunk} chunk * @property {ChunkGraph} chunkGraph * @property {function(string): any=} __webpack_require__ */ /** * @typedef {Object} EntryData * @property {Dependency[]} dependencies dependencies of the entrypoint that should be evaluated at startup * @property {Dependency[]} includeDependencies dependencies of the entrypoint that should be included but not evaluated * @property {EntryOptions} options options of the entrypoint */ /** * @typedef {Object} LogEntry * @property {string} type * @property {any[]} args * @property {number} time * @property {string[]=} trace */ /** * @typedef {Object} KnownAssetInfo * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash) * @property {boolean=} minimized whether the asset is minimized * @property {string | string[]=} fullhash the value(s) of the full hash used for this asset * @property {string | string[]=} chunkhash the value(s) of the chunk hash used for this asset * @property {string | string[]=} modulehash the value(s) of the module hash used for this asset * @property {string | string[]=} contenthash the value(s) of the content hash used for this asset * @property {string=} sourceFilename when asset was created from a source file (potentially transformed), the original filename relative to compilation context * @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) * @property {boolean=} javascriptModule true, when asset is javascript and an ESM * @property {Record<string, string | string[]>=} related object of pointers to other assets, keyed by type of relation (only points from parent to child) */ /** @typedef {KnownAssetInfo & Record<string, any>} AssetInfo */ /** * @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 */ /** * @typedef {Object} ModulePathData * @property {string|number} id * @property {string} hash * @property {function(number): string=} hashWithLength */ /** * @typedef {Object} PathData * @property {ChunkGraph=} chunkGraph * @property {string=} hash * @property {function(number): string=} hashWithLength * @property {(Chunk|ChunkPathData)=} chunk * @property {(Module|ModulePathData)=} module * @property {RuntimeSpec=} runtime * @property {string=} filename * @property {string=} basename * @property {string=} query * @property {string=} contentHashType * @property {string=} contentHash * @property {function(number): string=} contentHashWithLength * @property {boolean=} noChunkHash * @property {string=} url */ /** * @typedef {Object} KnownNormalizedStatsOptions * @property {string} context * @property {RequestShortener} requestShortener * @property {string} chunksSort * @property {string} modulesSort * @property {string} chunkModulesSort * @property {string} nestedModulesSort * @property {string} assetsSort * @property {boolean} ids * @property {boolean} cachedAssets * @property {boolean} groupAssetsByEmitStatus * @property {boolean} groupAssetsByPath * @property {boolean} groupAssetsByExtension * @property {number} assetsSpace * @property {((value: string, asset: StatsAsset) => boolean)[]} excludeAssets * @property {((name: string, module: StatsModule, type: "module" | "chunk" | "root-of-chunk" | "nested") => boolean)[]} excludeModules * @property {((warning: StatsError, textValue: string) => boolean)[]} warningsFilter * @property {boolean} cachedModules * @property {boolean} orphanModules * @property {boolean} dependentModules * @property {boolean} runtimeModules * @property {boolean} groupModulesByCacheStatus * @property {boolean} groupModulesByLayer * @property {boolean} groupModulesByAttributes * @property {boolean} groupModulesByPath * @property {boolean} groupModulesByExtension * @property {boolean} groupModulesByType * @property {boolean | "auto"} entrypoints * @property {boolean} chunkGroups * @property {boolean} chunkGroupAuxiliary * @property {boolean} chunkGroupChildren * @property {number} chunkGroupMaxAssets * @property {number} modulesSpace * @property {number} chunkModulesSpace * @property {number} nestedModulesSpace * @property {false|"none"|"error"|"warn"|"info"|"log"|"verbose"} logging * @property {((value: string) => boolean)[]} loggingDebug * @property {boolean} loggingTrace * @property {any} _env */ /** @typedef {KnownNormalizedStatsOptions & Omit<StatsOptions, keyof KnownNormalizedStatsOptions> & Record<string, any>} NormalizedStatsOptions */ /** * @typedef {Object} KnownCreateStatsOptionsContext * @property {boolean=} forToString */ /** @typedef {KnownCreateStatsOptionsContext & Record<string, any>} CreateStatsOptionsContext */ /** @type {AssetInfo} */ const EMPTY_ASSET_INFO = Object.freeze({}); const esmDependencyCategory = "esm"; // TODO webpack 6: remove const deprecatedNormalModuleLoaderHook = util.deprecate( compilation => { return require("./NormalModule").getCompilationHooks(compilation).loader; }, "Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader", "DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK" ); // TODO webpack 6: remove const defineRemovedModuleTemplates = moduleTemplates => { Object.defineProperties(moduleTemplates, { asset: { enumerable: false, configurable: false, get: () => { throw new WebpackError( "Compilation.moduleTemplates.asset has been removed" ); } }, webassembly: { enumerable: false, configurable: false, get: () => { throw new WebpackError( "Compilation.moduleTemplates.webassembly has been removed" ); } } }); moduleTemplates = undefined; }; const byId = compareSelect( /** * @param {Chunk} c chunk * @returns {number | string} id */ c => c.id, compareIds ); const byNameOrHash = concatComparators( compareSelect( /** * @param {Compilation} c compilation * @returns {string} name */ c => c.name, compareIds ), compareSelect( /** * @param {Compilation} c compilation * @returns {string} hash */ c => c.fullHash, compareIds ) ); const byMessage = compareSelect(err => `${err.message}`, compareStringsNumeric); const byModule = compareSelect( err => (err.module && err.module.identifier()) || "", compareStringsNumeric ); const byLocation = compareSelect(err => err.loc, compareLocations); const compareErrors = concatComparators(byModule, byLocation, byMessage); /** @type {WeakMap<Dependency, Module & { restoreFromUnsafeCache: Function } | null>} */ const unsafeCacheDependencies = new WeakMap(); /** @type {WeakMap<Module & { restoreFromUnsafeCache: Function }, object>} */ const unsafeCacheData = new WeakMap(); class Compilation { /** * Creates an instance of Compilation. * @param {Compiler} compiler the compiler which created the compilation * @param {CompilationParams} params the compilation parameters */ constructor(compiler, params) { this._backCompat = compiler._backCompat; const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this); /** @typedef {{ additionalAssets?: true | Function }} ProcessAssetsAdditionalOptions */ /** @type {AsyncSeriesHook<[CompilationAssets], ProcessAssetsAdditionalOptions>} */ const processAssetsHook = new AsyncSeriesHook(["assets"]); let savedAssets = new Set(); const popNewAssets = assets => { let newAssets = undefined; for (const file of Object.keys(assets)) { if (savedAssets.has(file)) continue; if (newAssets === undefined) { newAssets = Object.create(null); } newAssets[file] = assets[file]; savedAssets.add(file); } return newAssets; }; processAssetsHook.intercept({ name: "Compilation", call: () => { savedAssets = new Set(Object.keys(this.assets)); }, register: tap => { const { type, name } = tap; const { fn, additionalAssets, ...remainingTap } = tap; const additionalAssetsFn = additionalAssets === true ? fn : additionalAssets; const processedAssets = additionalAssetsFn ? new WeakSet() : undefined; switch (type) { case "sync": if (additionalAssetsFn) { this.hooks.processAdditionalAssets.tap(name, assets => { if (processedAssets.has(this.assets)) additionalAssetsFn(assets); }); } return { ...remainingTap, type: "async", fn: (assets, callback) => { try { fn(assets); } catch (e) { return callback(e); } if (processedAssets !== undefined) processedAssets.add(this.assets); const newAssets = popNewAssets(assets); if (newAssets !== undefined) { this.hooks.processAdditionalAssets.callAsync( newAssets, callback ); return; } callback(); } }; case "async": if (additionalAssetsFn) { this.hooks.processAdditionalAssets.tapAsync( name, (assets, callback) => { if (processedAssets.has(this.assets)) return additionalAssetsFn(assets, callback); callback(); } ); } return { ...remainingTap, fn: (assets, callback) => { fn(assets, err => { if (err) return callback(err); if (processedAssets !== undefined) processedAssets.add(this.assets); const newAssets = popNewAssets(assets); if (newAssets !== undefined) { this.hooks.processAdditionalAssets.callAsync( newAssets, callback ); return; } callback(); }); } }; case "promise": if (additionalAssetsFn) { this.hooks.processAdditionalAssets.tapPromise(name, assets => { if (processedAssets.has(this.assets)) return additionalAssetsFn(assets); return Promise.resolve(); }); } return { ...remainingTap, fn: assets => { const p = fn(assets); if (!p || !p.then) return p; return p.then(() => { if (processedAssets !== undefined) processedAssets.add(this.assets); const newAssets = popNewAssets(assets); if (newAssets !== undefined) { return this.hooks.processAdditionalAssets.promise( newAssets ); } }); } }; } } }); /** @type {SyncHook<[CompilationAssets]>} */ const afterProcessAssetsHook = new SyncHook(["assets"]); /** * @template T * @param {string} name name of the hook * @param {number} stage new stage * @param {function(): AsArray<T>} getArgs get old hook function args * @param {string=} code deprecation code (not deprecated when unset) * @returns {FakeHook<Pick<AsyncSeriesHook<T>, "tap" | "tapAsync" | "tapPromise" | "name">>} fake hook which redirects */ const createProcessAssetsHook = (name, stage, getArgs, code) => { if (!this._backCompat && code) return undefined; const errorMessage = reason => `Can't automatically convert plugin using Compilation.hooks.${name} to Compilation.hooks.processAssets because ${reason}. BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a single Compilation.hooks.processAssets hook.`; const getOptions = options => { if (typeof options === "string") options = { name: options }; if (options.stage) { throw new Error(errorMessage("it's using the 'stage' option")); } return { ...options, stage: stage }; }; return createFakeHook( { name, /** @type {AsyncSeriesHook<T>["intercept"]} */ intercept(interceptor) { throw new Error(errorMessage("it's using 'intercept'")); }, /** @type {AsyncSeriesHook<T>["tap"]} */ tap: (options, fn) => { processAssetsHook.tap(getOptions(options), () => fn(...getArgs())); }, /** @type {AsyncSeriesHook<T>["tapAsync"]} */ tapAsync: (options, fn) => { processAssetsHook.tapAsync( getOptions(options), (assets, callback) => /** @type {any} */ (fn)(...getArgs(), callback) ); }, /** @type {AsyncSeriesHook<T>["tapPromise"]} */ tapPromise: (options, fn) => { processAssetsHook.tapPromise(getOptions(options), () => fn(...getArgs()) ); } }, `${name} is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)`, code ); }; this.hooks = Object.freeze({ /** @type {SyncHook<[Module]>} */ buildModule: new SyncHook(["module"]), /** @type {SyncHook<[Module]>} */ rebuildModule: new SyncHook(["module"]), /** @type {SyncHook<[Module, WebpackError]>} */ failedModule: new SyncHook(["module", "error"]), /** @type {SyncHook<[Module]>} */ succeedModule: new SyncHook(["module"]), /** @type {SyncHook<[Module]>} */ stillValidModule: new SyncHook(["module"]), /** @type {SyncHook<[Dependency, EntryOptions]>} */ addEntry: new SyncHook(["entry", "options"]), /** @type {SyncHook<[Dependency, EntryOptions, Error]>} */ failedEntry: new SyncHook(["entry", "options", "error"]), /** @type {SyncHook<[Dependency, EntryOptions, Module]>} */ succeedEntry: new SyncHook(["entry", "options", "module"]), /** @type {SyncWaterfallHook<[(string[] | ReferencedExport)[], Dependency, RuntimeSpec]>} */ dependencyReferencedExports: new SyncWaterfallHook([ "referencedExports", "dependency", "runtime" ]), /** @type {SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */ executeModule: new SyncHook(["options", "context"]), /** @type {AsyncParallelHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */ prepareModuleExecution: new AsyncParallelHook(["options", "context"]), /** @type {AsyncSeriesHook<[Iterable<Module>]>} */ finishModules: new AsyncSeriesHook(["modules"]), /** @type {AsyncSeriesHook<[Module]>} */ finishRebuildingModule: new AsyncSeriesHook(["module"]), /** @type {SyncHook<[]>} */ unseal: new SyncHook([]), /** @type {SyncHook<[]>} */ seal: new SyncHook([]), /** @type {SyncHook<[]>} */ beforeChunks: new SyncHook([]), /** @type {SyncHook<[Iterable<Chunk>]>} */ afterChunks: new SyncHook(["chunks"]), /** @type {SyncBailHook<[Iterable<Module>]>} */ optimizeDependencies: new SyncBailHook(["modules"]), /** @type {SyncHook<[Iterable<Module>]>} */ afterOptimizeDependencies: new SyncHook(["modules"]), /** @type {SyncHook<[]>} */ optimize: new SyncHook([]), /** @type {SyncBailHook<[Iterable<Module>]>} */ optimizeModules: new SyncBailHook(["modules"]), /** @type {SyncHook<[Iterable<Module>]>} */ afterOptimizeModules: new SyncHook(["modules"]), /** @type {SyncBailHook<[Iterable<Chunk>, ChunkGroup[]]>} */ optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]), /** @type {SyncHook<[Iterable<Chunk>, ChunkGroup[]]>} */ afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]), /** @type {AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>} */ optimizeTree: new AsyncSeriesHook(["chunks", "modules"]), /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */ afterOptimizeTree: new SyncHook(["chunks", "modules"]), /** @type {AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>]>} */ optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]), /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */ afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]), /** @type {SyncBailHook<[], boolean>} */ shouldRecord: new SyncBailHook([]), /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */ additionalChunkRuntimeRequirements: new SyncHook([ "chunk", "runtimeRequirements", "context" ]), /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */ runtimeRequirementInChunk: new HookMap( () => new SyncBailHook(["chunk", "runtimeRequirements", "context"]) ), /** @type {SyncHook<[Module, Set<string>, RuntimeRequirementsContext]>} */ additionalModuleRuntimeRequirements: new SyncHook([ "module", "runtimeRequirements", "context" ]), /** @type {HookMap<SyncBailHook<[Module, Set<string>, RuntimeRequirementsContext]>>} */ runtimeRequirementInModule: new HookMap( () => new SyncBailHook(["module", "runtimeRequirements", "context"]) ), /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */ additionalTreeRuntimeRequirements: new SyncHook([ "chunk", "runtimeRequirements", "context" ]), /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */ runtimeRequirementInTree: new HookMap( () => new SyncBailHook(["chunk", "runtimeRequirements", "context"]) ), /** @type {SyncHook<[RuntimeModule, Chunk]>} */ runtimeModule: new SyncHook(["module", "chunk"]), /** @type {SyncHook<[Iterable<Module>, any]>} */ reviveModules: new SyncHook(["modules", "records"]), /** @type {SyncHook<[Iterable<Module>]>} */ beforeModuleIds: new SyncHook(["modules"]), /** @type {SyncHook<[Iterable<Module>]>} */ moduleIds: new SyncHook(["modules"]), /** @type {SyncHook<[Iterable<Module>]>} */ optimizeModuleIds: new SyncHook(["modules"]), /** @type {SyncHook<[Iterable<Module>]>} */ afterOptimizeModuleIds: new SyncHook(["modules"]), /** @type {SyncHook<[Iterable<Chunk>, any]>} */ reviveChunks: new SyncHook(["chunks", "records"]), /** @type {SyncHook<[Iterable<Chunk>]>} */ beforeChunkIds: new SyncHook(["chunks"]), /** @type {SyncHook<[Iterable<Chunk>]>} */ chunkIds: new SyncHook(["chunks"]), /** @type {SyncHook<[Iterable<Chunk>]>} */ optimizeChunkIds: new SyncHook(["chunks"]), /** @type {SyncHook<[Iterable<Chunk>]>} */ afterOptimizeChunkIds: new SyncHook(["chunks"]), /** @type {SyncHook<[Iterable<Module>, any]>} */ recordModules: new SyncHook(["modules", "records"]), /** @type {SyncHook<[Iterable<Chunk>, any]>} */ recordChunks: new SyncHook(["chunks", "records"]), /** @type {SyncHook<[Iterable<Module>]>} */ optimizeCodeGeneration: new SyncHook(["modules"]), /** @type {SyncHook<[]>} */ beforeModuleHash: new SyncHook([]), /** @type {SyncHook<[]>} */ afterModuleHash: new SyncHook([]), /** @type {SyncHook<[]>} */ beforeCodeGeneration: new SyncHook([]), /** @type {SyncHook<[]>} */ afterCodeGeneration: new SyncHook([]), /** @type {SyncHook<[]>} */ beforeRuntimeRequirements: new SyncHook([]), /** @type {SyncHook<[]>} */ afterRuntimeRequirements: new SyncHook([]), /** @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<[], boolean>} */ shouldGenerateChunkAssets: new SyncBailHook([]), /** @type {SyncHook<[]>} */ beforeChunkAssets: new SyncHook([]), // TODO webpack 6 remove /** @deprecated */ additionalChunkAssets: createProcessAssetsHook( "additionalChunkAssets", Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, () => [this.chunks], "DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS" ), // TODO webpack 6 deprecate /** @deprecated */ additionalAssets: createProcessAssetsHook( "additionalAssets", Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, () => [] ), // TODO webpack 6 remove /** @deprecated */ optimizeChunkAssets: createProcessAssetsHook( "optimizeChunkAssets", Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE, () => [this.chunks], "DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS" ), // TODO webpack 6 remove /** @deprecated */ afterOptimizeChunkAssets: createProcessAssetsHook( "afterOptimizeChunkAssets", Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1, () => [this.chunks], "DEP_WEBPACK_COMPILATION_AFTER_OPTIMIZE_CHUNK_ASSETS" ), // TODO webpack 6 deprecate /** @deprecated */ optimizeAssets: processAssetsHook, // TODO webpack 6 deprecate /** @deprecated */ afterOptimizeAssets: afterProcessAssetsHook, processAssets: processAssetsHook, afterProcessAssets: afterProcessAssetsHook, /** @type {AsyncSeriesHook<[CompilationAssets]>} */ processAdditionalAssets: new AsyncSeriesHook(["assets"]), /** @type {SyncBailHook<[], boolean>} */ needAdditionalSeal: new SyncBailHook([]), /** @type {AsyncSeriesHook<[]>} */ afterSeal: new AsyncSeriesHook([]), /** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */ renderManifest: new SyncWaterfallHook(["result", "options"]), /** @type {SyncHook<[Hash]>} */ fullHash: new SyncHook(["hash"]), /** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */ chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]), /** @type {SyncHook<[Module, string]>} */ moduleAsset: new SyncHook(["module", "filename"]), /** @type {SyncHook<[Chunk, string]>} */ chunkAsset: new SyncHook(["chunk", "filename"]), /** @type {SyncWaterfallHook<[string, object, AssetInfo]>} */ assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]), /** @type {SyncBailHook<[], boolean>} */ needAdditionalPass: new SyncBailHook([]), /** @type {SyncHook<[Compiler, string, number]>} */ childCompiler: new SyncHook([ "childCompiler", "compilerName", "compilerIndex" ]), /** @type {SyncBailHook<[string, LogEntry], true>} */ log: new SyncBailHook(["origin", "logEntry"]), /** @type {SyncWaterfallHook<[WebpackError[]]>} */ processWarnings: new SyncWaterfallHook(["warnings"]), /** @type {SyncWaterfallHook<[WebpackError[]]>} */ processErrors: new SyncWaterfallHook(["errors"]), /** @type {HookMap<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>} */ statsPreset: new HookMap(() => new SyncHook(["options", "context"])), /** @type {SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>} */ statsNormalize: new SyncHook(["options", "context"]), /** @type {SyncHook<[StatsFactory, NormalizedStatsOptions]>} */ statsFactory: new SyncHook(["statsFactory", "options"]), /** @type {SyncHook<[StatsPrinter, NormalizedStatsOptions]>} */ statsPrinter: new SyncHook(["statsPrinter", "options"]), get normalModuleLoader() { return getNormalModuleLoader(); } }); /** @type {string=} */ this.name = undefined; this.startTime = undefined; this.endTime = undefined; /** @type {Compiler} */ this.compiler = compiler; this.resolverFactory = compiler.resolverFactory; this.inputFileSystem = compiler.inputFileSystem; this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, { managedPaths: compiler.managedPaths, immutablePaths: compiler.immutablePaths, logger: this.getLogger("webpack.FileSystemInfo"), hashFunction: compiler.options.output.hashFunction }); if (compiler.fileTimestamps) { this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true); } if (compiler.contextTimestamps) { this.fileSystemInfo.addContextTimestamps( compiler.contextTimestamps, true ); } /** @type {Map<string, string | Set<string>>} */ this.valueCacheVersions = new Map(); this.requestShortener = compiler.requestShortener; this.compilerPath = compiler.compilerPath; this.logger = this.getLogger("webpack.Compilation"); const options = compiler.options; this.options = options; this.outputOptions = options && options.output; /** @type {boolean} */ this.bail = (options && options.bail) || false; /** @type {boolean} */ this.profile = (options && options.profile) || false; this.params = params; this.mainTemplate = new MainTemplate(this.outputOptions, this); this.chunkTemplate = new ChunkTemplate(this.outputOptions, this); this.runtimeTemplate = new RuntimeTemplate( this, this.outputOptions, this.requestShortener ); /** @type {{javascript: ModuleTemplate}} */ this.moduleTemplates = { javascript: new ModuleTemplate(this.runtimeTemplate, this) }; defineRemovedModuleTemplates(this.moduleTemplates); /** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */ this.moduleMemCaches = undefined; /** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */ this.moduleMemCaches2 = undefined; this.moduleGraph = new ModuleGraph(); /** @type {ChunkGraph} */ this.chunkGraph = undefined; /** @type {CodeGenerationResults} */ this.codeGenerationResults = undefined; /** @type {AsyncQueue<Module, Module, Module>} */ this.processDependenciesQueue = new AsyncQueue({ name: "processDependencies", parallelism: options.parallelism || 100, processor: this._processModuleDependencies.bind(this) }); /** @type {AsyncQueue<Module, string, Module>} */ this.addModuleQueue = new AsyncQueue({ name: "addModule", parent: this.processDependenciesQueue, getKey: module => module.identifier(), processor: this._addModule.bind(this) }); /** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */ this.factorizeQueue = new AsyncQueue({ name: "factorize", parent: this.addModuleQueue, processor: this._factorizeModule.bind(this) }); /** @type {AsyncQueue<Module, Module, Module>} */ this.buildQueue = new AsyncQueue({ name: "build", parent: this.factorizeQueue, processor: this._buildModule.bind(this) }); /** @type {AsyncQueue<Module, Module, Module>} */ this.rebuildQueue = new AsyncQueue({ name: "rebuild", parallelism: options.parallelism || 100, processor: this._rebuildModule.bind(this) }); /** * Modules in value are building during the build of Module in key. * Means value blocking key from finishing. * Needed to detect build cycles. * @type {WeakMap<Module, Set<Module>>} */ this.creatingModuleDuringBuild = new WeakMap(); /** @type {Map<string, EntryData>} */ this.entries = new Map(); /** @type {EntryData} */ this.globalEntry = { dependencies: [], includeDependencies: [], options: { name: undefined } }; /** @type {Map<string, Entrypoint>} */ this.entrypoints = new Map(); /** @type {Entrypoint[]} */ this.asyncEntrypoints = []; /** @type {Set<Chunk>} */ this.chunks = new Set(); /** @type {ChunkGroup[]} */ this.chunkGroups = []; /** @type {Map<string, ChunkGroup>} */ this.namedChunkGroups = new Map(); /** @type {Map<string, Chunk>} */ this.namedChunks = new Map(); /** @type {Set<Module>} */ this.modules = new Set(); if (this._backCompat) { arrayToSetDeprecation(this.chunks, "Compilation.chunks"); arrayToSetDeprecation(this.modules, "Compilation.modules"); } /** @private @type {Map<string, Module>} */ this._modules = new Map(); this.records = null; /** @type {string[]} */ this.additionalChunkAssets = []; /** @type {CompilationAssets} */ this.assets = {}; /** @type {Map<string, AssetInfo>} */ this.assetsInfo = new Map(); /** @type {Map<string, Map<string, Set<string>>>} */ this._assetsRelatedIn = 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 {DependencyTemplates} */ this.dependencyTemplates = new DependencyTemplates( this.outputOptions.hashFunction ); this.childrenCounters = {}; /** @type {Set<number|string>} */ this.usedChunkIds = null; /** @type {Set<number>} */ this.usedModuleIds = null; /** @type {boolean} */ this.needAdditionalPass = false; /** @type {Set<Module & { restoreFromUnsafeCache: Function }>} */ this._restoredUnsafeCacheModuleEntries = new Set(); /** @type {Map<string, Module & { restoreFromUnsafeCache: Function }>} */ this._restoredUnsafeCacheEntries = new Map(); /** @type {WeakSet<Module>} */ this.builtModules = new WeakSet(); /** @type {WeakSet<Module>} */ this.codeGeneratedModules = new WeakSet(); /** @type {WeakSet<Module>} */ this.buildTimeExecutedModules = new WeakSet(); /** @private @type {Map<Module, Callback[]>} */ this._rebuildingModules = new Map(); /** @type {Set<string>} */ this.emittedAssets = new Set(); /** @type {Set<string>} */ this.comparedForEmitAssets = new Set(); /** @type {LazySet<string>} */ this.fileDependencies = new LazySet(); /** @type {LazySet<string>} */ this.contextDependencies = new LazySet(); /** @type {LazySet<string>} */ this.missingDependencies = new LazySet(); /** @type {LazySet<string>} */ this.buildDependencies = new LazySet(); // TODO webpack 6 remove this.compilationDependencies = { add: util.deprecate( item => this.fileDependencies.add(item), "Compilation.compilationDependencies is deprecated (used Compilation.fileDependencies instead)", "DEP_WEBPACK_COMPILATION_COMPILATION_DEPENDENCIES" ) }; this._modulesCache = this.getCache("Compilation/modules"); this._assetsCache = this.getCache("Compilation/assets"); this._codeGenerationCache = this.getCache("Compilation/codeGeneration"); const unsafeCache = options.module.unsafeCache; this._unsafeCache = !!unsafeCache; this._unsafeCachePredicate = typeof unsafeCache === "function" ? unsafeCache : () => true; } getStats() { return new Stats(this); } /** * @param {StatsOptions | string} optionsOrPreset stats option value * @param {CreateStatsOptionsContext} context context * @returns {NormalizedStatsOptions} normalized options */ createStatsOptions(optionsOrPreset, context = {}) { if ( typeof optionsOrPreset === "boolean" || typeof optionsOrPreset === "string" ) { optionsOrPreset = { preset: optionsOrPreset }; } if (typeof optionsOrPreset === "object" && optionsOrPreset !== null) { // We use this method of shallow cloning this object to include // properties in the prototype chain /** @type {Partial<NormalizedStatsOptions>} */ const options = {}; for (const key in optionsOrPreset) { options[key] = optionsOrPreset[key]; } if (options.preset !== undefined) { this.hooks.statsPreset.for(options.preset).call(options, context); } this.hooks.statsNormalize.call(options, context); return /** @type {NormalizedStatsOptions} */ (options); } else { /** @type {Partial<NormalizedStatsOptions>} */ const options = {}; this.hooks.statsNormalize.call(options, context); return /** @type {NormalizedStatsOptions} */ (options); } } createStatsFactory(options) { const statsFactory = new StatsFactory(); this.hooks.statsFactory.call(statsFactory, options); return statsFactory; } createStatsPrinter(options) { const statsPrinter = new StatsPrinter(); this.hooks.statsPrinter.call(statsPrinter, options); return statsPrinter; } /** * @param {string} name cache name * @returns {CacheFacade} the cache facade instance */ getCache(name) { return this.compiler.getCache(name); } /** * @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]}`); } } } }, childName => { if (typeof name === "function") { if (typeof childName === "function") { return this.getLogger(() => { if (typeof name === "function") { name = name(); if (!name) { throw new TypeError( "Compilation.getLogger(name) called with a function not returning a name" ); } } if (typeof childName === "function") { childName = childName(); if (!childName) { throw new TypeError( "Logger.getChildLogger(name) called with a function not returning a name" ); } } return `${name}/${childName}`; }); } else { return this.getLogger(() => { if (typeof name === "function") { name = name(); if (!name) { throw new TypeError( "Compilation.getLogger(name) called with a function not returning a name" ); } } return `${name}/${childName}`; }); } } else { if (typeof childName === "function") { return this.getLogger(() => { if (typeof childName === "function") { childName = childName(); if (!childName) { throw new TypeError( "Logger.getChildLogger(name) called with a function not returning a name" ); } } return `${name}/${childName}`; }); } else { return this.getLogger(`${name}/${childName}`); } } } ); } /** * @param {Module} module module to be added that was created * @param {ModuleCallback} callback returns the module in the compilation, * it could be the passed one (if new), or an already existing in the compilation * @returns {void} */ addModule(module, callback) { this.addModuleQueue.add(module, callback); } /** * @param {Module} module module to be added that was created * @param {ModuleCallback} callback returns the module in the compilation, * it could be the passed one (if new), or an already existing in the compilation * @returns {void} */ _addModule(module, callback) { const identifier = module.identifier(); const alreadyAddedModule = this._modules.get(identifier); if (alreadyAddedModule) { return callback(null, alreadyAddedModule); } const currentProfile = this.profile ? this.moduleGraph.getProfile(module) : undefined; if (currentProfile !== undefined) { currentProfile.markRestoringStart(); } this._modulesCache.get(identifier, null, (err, cacheModule) => { if (err) return callback(new ModuleRestoreError(module, err)); if (currentProfile !== undefined) { currentProfile.markRestoringEnd(); currentProfile.markIntegrationStart(); } if (cacheModule) { cacheModule.updateCacheModule(module); module = cacheModule; } this._modules.set(identifier, module); this.modules.add(module); if (this._backCompat) ModuleGraph.setModuleGraphForModule(module, this.moduleGraph); if (currentProfile !== undefined) { currentProfile.markIntegrationEnd(); } callback(null, module); }); } /** * 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); } /** * Schedules a build of the module object * * @param {Module} module module to be built * @param {ModuleCallback} callback the callback * @returns {void} */ buildModule(module, callback) { this.buildQueue.add(module, callback); } /** * Builds the module object * * @param {Module} module module to be built * @param {ModuleCallback} callback the callback * @returns {void} */ _buildModule(module, callback) { const currentProfile = this.profile ? this.moduleGraph.getProfile(module) : undefined; if (currentProfile !== undefined) { currentProfile.markBuildingStart(); } module.needBuild( { compilation: this, fileSystemInfo: this.fileSystemInfo, valueCacheVersions: this.valueCacheVersions }, (err, needBuild) => { if (err) return callback(err); if (!needBuild) { if (currentProfile !== undefined) { currentProfile.markBuildingEnd(); } this.hooks.stillValidModule.call(module); return callback(); } this.hooks.buildModule.call(module); this.builtModules.add(module); module.build( this.options, this, this.resolverFactory.get("normal", module.resolveOptions), this.inputFileSystem, err => { if (currentProfile !== undefined) { currentProfile.markBuildingEnd(); } if (err) { this.hooks.failedModule.call(module, err); return callback(err); } if (currentProfile !== undefined) { currentProfile.markStoringStart(); } this._modulesCache.store(module.identifier(), null, module, err => { if (currentProfile !== undefined) { currentProfile.markStoringEnd(); } if (err) { this.hooks.failedModule.call(module, err); return callback(new ModuleStoreError(module, err)); } 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) { this.processDependenciesQueue.add(module, callback); } /** * @param {Module} module to be processed for deps * @returns {void} */ processModuleDependenciesNonRecursive(module) { const processDependenciesBlock = block => { if (block.dependencies) { let i = 0; for (const dep of block.dependencies) { this.moduleGraph.setParents(dep, block, module, i++); } } if (block.blocks) { for (const b of block.blocks) processDependenciesBlock(b); } }; processDependenciesBlock(module); } /** * @param {Module} module to be processed for deps * @param {ModuleCallback} callback callback to be triggered * @returns {void} */ _processModuleDependencies(module, callback) { /** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], context: string|undefined, originModule: Module|null}>} */ const sortedDependencies = []; /** @type {DependenciesBlock} */ let currentBlock; /** @type {Map<ModuleFactory, Map<string, Dependency[]>>} */ let dependencies; /** @type {DepConstructor} */ let factoryCacheKey; /** @type {ModuleFactory} */ let factoryCacheKey2; /** @type {Map<string, Dependency[]>} */ let factoryCacheValue; /** @type {string} */ let listCacheKey1; /** @type {string} */ let listCacheKey2; /** @type {Dependency[]} */ let listCacheValue; let inProgressSorting = 1; let inProgressTransitive = 1; const onDependenciesSorted = err => { if (err) return callback(err); // early exit without changing parallelism back and forth if (sortedDependencies.length === 0 && inProgressTransitive === 1) { return callback(); } // This is nested so we need to allow one additional task this.processDependenciesQueue.increaseParallelism(); for (const item of sortedDependencies) { inProgressTransitive++; this.handleModuleCreation(item, 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 && this.bail) { if (inProgressTransitive <= 0) return; inProgressTransitive = -1; // eslint-disable-next-line no-self-assign err.stack = err.stack; onTransitiveTasksFinished(err); return; } if (--inProgressTransitive === 0) onTransitiveTasksFinished(); }); } if (--inProgressTransitive === 0) onTransitiveTasksFinished(); }; const onTransitiveTasksFinished = err => { if (err) return callback(err); this.processDependenciesQueue.decreaseParallelism(); return callback(); }; /** * @param {Dependency} dep dependency * @param {number} index index in block * @returns {void} */ const processDependency = (dep, index) => { this.moduleGraph.setParents(dep, currentBlock, module, index); if (this._unsafeCache) { try { const unsafeCachedModule = unsafeCacheDependencies.get(dep); if (unsafeCachedModule === null) return; if (unsafeCachedModule !== undefined) { if ( this._restoredUnsafeCacheModuleEntries.has(unsafeCachedModule) ) { this._handleExistingModuleFromUnsafeCache( module, dep, unsafeCachedModule ); return; } const identifier = unsafeCachedModule.identifier(); const cachedModule = this._restoredUnsafeCacheEntries.get(identifier); if (cachedModule !== undefined) { // update unsafe cache to new module unsafeCacheDependencies.set(dep, cachedModule); this._handleExistingModuleFromUnsafeCache( module, dep, cachedModule ); return; } inProgressSorting++; this._modulesCache.get(identifier, null, (err, cachedModule) => { if (err) { if (inProgressSorting <= 0) return; inProgressSorting = -1; onDependenciesSorted(err); return; } try { if (!this._restoredUnsafeCacheEntries.has(identifier)) { const data = unsafeCacheData.get(cachedModule); if (data === undefined) { processDependencyForResolving(dep); if (--inProgressSorting === 0) onDependenciesSorted(); return; } if (cachedModule !== unsafeCachedModule) { unsafeCacheDependencies.set(dep, cachedModule); } cachedModule.restoreFromUnsafeCache( data, this.params.normalModuleFactory, this.params ); this._restoredUnsafeCacheEntries.set( identifier, cachedModule ); this._restoredUnsafeCacheModuleEntries.add(cachedModule); if (!this.modules.has(cachedModule)) { inProgressTransitive++; this._handleNewModuleFromUnsafeCache( module, dep, cachedModule, err => { if (err) { if (inProgressTransitive <= 0) return; inProgressTransitive = -1; onTransitiveTasksFinished(err); } if (--inProgressTransitive === 0) return onTransitiveTasksFinished(); } ); if (--inProgressSorting === 0) onDependenciesSorted(); return; } } if (unsafeCachedModule !== cachedModule) { unsafeCacheDependencies.set(dep, cachedModule); } this._handleExistingModuleFromUnsafeCache( module, dep, cachedModule ); // a3 } catch (err) { if (inProgressSorting <= 0) return; inProgressSorting = -1; onDependenciesSorted(err); return; } if (--inProgressSorting === 0) onDependenciesSorted(); }); return; } } catch (e) { console.error(e); } } processDependencyForResolving(dep); }; /** * @param {Dependency} dep dependency * @returns {void} */ const processDependencyForResolving = dep => { const resourceIdent = dep.getResourceIdentifier(); if (resourceIdent !== undefined && resourceIdent !== null) { const category = dep.category; const constructor = /** @type {DepConstructor} */ (dep.constructor); if (factoryCacheKey === constructor) { // Fast path 1: same constructor as prev item if (listCacheKey1 === category && listCacheKey2 === resourceIdent) { // Super fast path 1: also same resource listCacheValue.push(dep); return; } } else { const factory = this.dependencyFactories.get(constructor); if (factory === undefined) { throw new Error( `No module factory available for dependency type: ${constructor.name}` ); } if (factoryCacheKey2 === factory) { // Fast path 2: same factory as prev item factoryCacheKey = constructor; if (listCacheKey1 === category && listCacheKey2 === resourceIdent) { // Super fast path 2: also same resource listCacheValue.push(dep); return; } } else { // Slow path if (factoryCacheKey2 !== undefined) { // Archive last cache entry if (dependencies === undefined) dependencies = new Map(); dependencies.set(factoryCacheKey2, factoryCacheValue); factoryCacheValue = dependencies.get(factory); if (factoryCacheValue === undefined) { factoryCacheValue = new Map(); } } else { factoryCacheValue = new Map(); } factoryCacheKey = constructor; factoryCacheKey2 = factory; } } // Here webpack is using heuristic that assumes // mostly esm dependencies would be used // so we don't allocate extra string for them const cacheKey = category === esmDependencyCategory ? resourceIdent : `${category}${resourceIdent}`; let list = factoryCacheValue.get(cacheKey); if (list === undefined) { factoryCacheValue.set(cacheKey, (list = [])); sortedDependencies.push({ factory: factoryCacheKey2, dependencies: list, context: dep.getContext(), originModule: module }); } list.push(dep); listCacheKey1 = category; listCacheKey2 = resourceIdent; listCacheValue = list; } }; try { /** @type {DependenciesBlock[]} */ const queue = [module]; do { const block = queue.pop(); if (block.dependencies) { currentBlock = block; let i = 0; for (const dep of block.dependencies) processDependency(dep, i++); } if (block.blocks) { for (const b of block.blocks) queue.push(b); } } while (queue.length !== 0); } catch (e) { return callback(e); } if (--inProgressSorting === 0) onDependenciesSorted(); } _handleNewModuleFromUnsafeCache(originModule, dependency, module, callback) { const moduleGraph = this.moduleGraph; moduleGraph.setResolvedModule(originModule, dependency, module); moduleGraph.setIssuerIfUnset( module, originModule !== undefined ? originModule : null ); this._modules.set(module.identifier(), module); this.modules.add(module); if (this._backCompat) ModuleGraph.setModuleGraphForModule(module, this.moduleGraph); this._handleModuleBuildAndDependencies( originModule, module, true, callback ); } _handleExistingModuleFromUnsafeCache(originModule, dependency, module) { const moduleGraph = this.moduleGraph; moduleGraph.setResolvedModule(originModule, dependency, module); } /** * @typedef {Object} HandleModuleCreationOptions * @property {ModuleFactory} factory * @property {Dependency[]} dependencies * @property {Module | null} originModule * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo * @property {string=} context * @property {boolean=} recursive recurse into dependencies of the created module * @property {boolean=} connectOrigin connect the resolved module with the origin module */ /** * @param {HandleModuleCreationOptions} options options object * @param {ModuleCallback} callback callback * @returns {void} */ handleModuleCreation( { factory, dependencies, originModule, contextInfo, context, recursive = true, connectOrigin = recursive }, callback ) { const moduleGraph = this.moduleGraph; const currentProfile = this.profile ? new ModuleProfile() : undefined; this.factorizeModule( { currentProfile, factory, dependencies, factoryResult: true, originModule, contextInfo, context }, (err, factoryResult) => { const applyFactoryResultDependencies = () => { const { fileDependencies, contextDependencies, missingDependencies } = factoryResult; if (fileDependencies) { this.fileDependencies.addAll(fileDependencies); } if (contextDependencies) { this.contextDependencies.addAll(contextDependencies); } if (missingDependencies) { this.missingDependencies.addAll(missingDependencies); } }; if (err) { if (factoryResult) applyFactoryResultDependencies(); if (dependencies.every(d => d.optional)) { this.warnings.push(err); return callback(); } else { this.errors.push(err); return callback(err); } } const newModule = factoryResult.module; if (!newModule) { applyFactoryResultDependencies(); return callback(); } if (currentProfile !== undefined) { moduleGraph.setProfile(newModule, currentProfile); } this.addModule(newModule, (err, module) => { if (err) { applyFactoryResultDependencies(); if (!err.module) { err.module = module; } this.errors.push(err); return callback(err); } if ( this._unsafeCache && factoryResult.cacheable !== false && /** @type {any} */ (module).restoreFromUnsafeCache && this._unsafeCachePredicate(module) ) { const unsafeCacheableModule = /** @type {Module & { restoreFromUnsafeCache: Function }} */ ( module ); for (let i = 0; i < dependencies.length; i++) { const dependency = dependencies[i]; moduleGraph.setResolvedModule( connectOrigin ? originModule : null, dependency, unsafeCacheableModule ); unsafeCacheDependencies.set(dependency, unsafeCacheableModule); } if (!unsafeCacheData.has(unsafeCacheableModule)) { unsafeCacheData.set( unsafeCacheableModule, unsafeCacheableModule.getUnsafeCacheData() ); } } else { applyFactoryResultDependencies(); for (let i = 0; i < dependencies.length; i++) { const dependency = dependencies[i]; moduleGraph.setResolvedModule( connectOrigin ? originModule : null, dependency, module ); } } moduleGraph.setIssuerIfUnset( module, originModule !== undefined ? originModule : null ); if (module !== newModule) { if (currentProfile !== undefined) { const otherProfile = moduleGraph.getProfile(module); if (otherProfile !== undefined) { currentProfile.mergeInto(otherProfile); } else { moduleGraph.setProfile(module, currentProfile); } } } this._handleModuleBuildAndDependencies( originModule, module, recursive, callback ); }); } ); } _handleModuleBuildAndDependencies(originModule, module, recursive, callback) { // Check for cycles when build is trigger inside another build let creatingModuleDuringBuildSet = undefined; if (!recursive && this.buildQueue.isProcessing(originModule)) { // Track build dependency creatingModuleDuringBuildSet = this.creatingModuleDuringBuild.get(originModule); if (creatingModuleDuringBuildSet === undefined) { creatingModuleDuringBuildSet = new Set(); this.creatingModuleDuringBuild.set( originModule, creatingModuleDuringBuildSet ); } creatingModuleDuringBuildSet.add(module); // When building is blocked by another module // search for a cycle, cancel the cycle by throwing // an error (otherwise this would deadlock) const blockReasons = this.creatingModuleDuringBuild.get(module); if (blockReasons !== undefined) { const set = new Set(blockReasons); for (const item of set) { const blockReasons = this.creatingModuleDuringBuild.get(item); if (blockReasons !== undefined) { for (const m of blockReasons) { if (m === module) { return callback(new BuildCycleError(module)); } set.add(m); } } } } } this.buildModule(module, err => { if (creatingModuleDuringBuildSet !== undefined) { creatingModuleDuringBuildSet.delete(module); } if (err) { if (!err.module) { err.module = module; } this.errors.push(err); return callback(err); } if (!recursive) { this.processModuleDependenciesNonRecursive(module); callback(null, module); return; } // This avoids deadlocks for circular dependencies if (this.processDependenciesQueue.isProcessing(module)) { return callback(); } this.processModuleDependencies(module, err => { if (err) { return callback(err); } callback(null, module); }); }); } /** * @param {FactorizeModuleOptions} options options object * @param {ModuleOrFactoryResultCallback} callback callback * @returns {void} */ _factorizeModule( { currentProfile, factory, dependencies, originModule, factoryResult, contextInfo, context }, callback ) { if (currentProfile !== undefined) { currentProfile.markFactoryStart(); } factory.create( { contextInfo: { issuer: originModule ? originModule.nameForCondition() : "", issuerLayer: originModule ? originModule.layer : null, compiler: this.compiler.name, ...contextInfo }, resolveOptions: originModule ? originModule.resolveOptions : undefined, context: context ? context : originModule ? originModule.context : this.compiler.context, dependencies: dependencies }, (err, result) => { if (result) { // TODO webpack 6: remove // For backward-compat if (result.module === undefined && result instanceof Module) { result = { module: result }; } if (!factoryResult) { const { fileDependencies, contextDependencies, missingDependencies } = result; if (fileDependencies) { this.fileDependencies.addAll(fileDependencies); } if (contextDependencies) { this.contextDependencies.addAll(contextDependencies); } if (missingDependencies) { this.missingDependencies.addAll(missingDependencies); } } } if (err) { const notFoundError = new ModuleNotFoundError( originModule, err, dependencies.map(d => d.loc).filter(Boolean)[0] ); return callback(notFoundError, factoryResult ? result : undefined); } if (!result) { return callback(); } if (currentProfile !== undefined) { currentProfile.markFactoryEnd(); } callback(null, factoryResult ? result : result.module); } ); } /** * @param {string} context context string path * @param {Dependency} dependency dependency used to create Module chain * @param {ModuleCallback} callback callback for when module chain is complete * @returns {void} will throw if dependency instance is not a valid Dependency */ addModuleChain(context, dependency, callback) { return this.addModuleTree({ context, dependency }, callback); } /** * @param {Object} options options * @param {string} options.context context string path * @param {Dependency} options.dependency dependency used to create Module chain * @param {Partial<ModuleFactoryCreateDataContextInfo>=} options.contextInfo additional context info for the root module * @param {ModuleCallback} callback callback for when module chain is complete * @returns {void} will throw if dependency instance is not a valid Dependency */ addModuleTree({ context, dependency, contextInfo }, callback) { if ( typeof dependency !== "object" || dependency === null || !dependency.constructor ) { return callback( new WebpackError("Parameter 'dependency' must be a Dependency") ); } const Dep = /** @type {DepConstructor} */ (dependency.constructor); const moduleFactory = this.dependencyFactories.get(Dep); if (!moduleFactory) { return callback( new WebpackError( `No dependency factory available for this dependency type: ${dependency.constructor.name}` ) ); } this.handleModuleCreation( { factory: moduleFactory, dependencies: [dependency], originModule: null, contextInfo, context }, (err, result) => { if (err && this.bail) { callback(err); this.buildQueue.stop(); this.rebuildQueue.stop(); this.processDependenciesQueue.stop(); this.factorizeQueue.stop(); } else if (!err && result) { callback(null, result); } else { callback(); } } ); } /** * @param {string} context context path for entry * @param {Dependency} entry entry dependency that should be followed * @param {string | EntryOptions} optionsOrName options or deprecated name of entry * @param {ModuleCallback} callback callback function * @returns {void} returns */ addEntry(context, entry, optionsOrName, callback) { // TODO webpack 6 remove const options = typeof optionsOrName === "object" ? optionsOrName : { name: optionsOrName }; this._addEntryItem(context, entry, "dependencies", options, callback); } /** * @param {string} context context path for entry * @param {Dependency} dependency dependency that should be followed * @param {EntryOptions} options options * @param {ModuleCallback} callback callback function * @returns {void} returns */ addInclude(context, dependency, options, callback) { this._addEntryItem( context, dependency, "includeDependencies", options, callback ); } /** * @param {string} context context path for entry * @param {Dependency} entry entry dependency that should be followed * @param {"dependencies" | "includeDependencies"} target type of entry * @param {EntryOptions} options options * @param {ModuleCallback} callback callback function * @returns {void} returns */ _addEntryItem(context, entry, target, options, callback) { const { name } = options; let entryData = name !== undefined ? this.entries.get(name) : this.globalEntry; if (entryData === undefined) { entryData = { dependencies: [], includeDependencies: [], options: { name: undefined, ...options } }; entryData[target].push(entry); this.entries.set(name, entryData); } else { entryData[target].push(entry); for (const key of Object.keys(options)) { if (options[key] === undefined) continue; if (entryData.options[key] === options[key]) continue; if ( Array.isArray(entryData.options[key]) && Array.isArray(options[key]) && arrayEquals(entryData.options[key], options[key]) ) { continue; } if (entryData.options[key] === undefined) { entryData.options[key] = options[key]; } else { return callback( new WebpackError( `Conflicting entry option ${key} = ${entryData.options[key]} vs ${options[key]}` ) ); } } } this.hooks.addEntry.call(entry, options); this.addModuleTree( { context, dependency: entry, contextInfo: entryData.options.layer ? { issuerLayer: entryData.options.layer } : undefined }, (err, module) => { if (err) { this.hooks.failedEntry.call(entry, options, err); return callback(err); } this.hooks.succeedEntry.call(entry, options, module); return callback(null, module); } ); } /** * @param {Module} module module to be rebuilt * @param {ModuleCallback} callback callback when module finishes rebuilding * @returns {void} */ rebuildModule(module, callback) { this.rebuildQueue.add(module, callback); } /** * @param {Module} module module to be rebuilt * @param {ModuleCallback} callback callback when module finishes rebuilding * @returns {void} */ _rebuildModule(module, callback) { this.hooks.rebuildModule.call(module); const oldDependencies = module.dependencies.slice(); const oldBlocks = module.blocks.slice(); module.invalidateBuild(); this.buildQueue.invalidate(module); this.buildModule(module, err => { if (err) { return this.hooks.finishRebuildingModule.callAsync(module, err2 => { if (err2) { callback( makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule") ); return; } callback(err); }); } this.processDependenciesQueue.invalidate(module); this.moduleGraph.unfreeze(); this.processModuleDependencies(module, err => { if (err) return callback(err); this.removeReasonsOfDependencyBlock(module, { dependencies: oldDependencies, blocks: oldBlocks }); this.hooks.finishRebuildingModule.callAsync(module, err2 => { if (err2) { callback( makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule") ); return; } callback(null, module); }); }); }); } _computeAffectedModules(modules) { const moduleMemCacheCache = this.compiler.moduleMemCaches; if (!moduleMemCacheCache) return; if (!this.moduleMemCaches) { this.moduleMemCaches = new Map(); this.moduleGraph.setModuleMemCaches(this.moduleMemCaches); } const { moduleGraph, moduleMemCaches } = this; const affectedModules = new Set(); const infectedModules = new Set(); let statNew = 0; let statChanged = 0; let statUnchanged = 0; let statReferencesChanged = 0; let statWithoutBuild = 0; const computeReferences = module => { /** @type {WeakMap<Dependency, Module>} */ let references = undefined; for (const connection of moduleGraph.getOutgoingConnections(module)) { const d = connection.dependency; const m = connection.module; if (!d || !m || unsafeCacheDependencies.has(d)) continue; if (references === undefined) references = new WeakMap(); references.set(d, m); } return references; }; /** * @param {Module} module the module * @param {WeakMap<Dependency, Module>} references references * @returns {boolean} true, when the references differ */ const compareReferences = (module, references) => { if (references === undefined) return true; for (const connection of moduleGraph.getOutgoingConnections(module)) { const d = connection.dependency; if (!d) continue; const entry = references.get(d); if (entry === undefined) continue; if (entry !== connection.module) return false; } return true; }; const modulesWithoutCache = new Set(modules); for (const [module, cachedMemCache] of moduleMemCacheCache) { if (modulesWithoutCache.has(module)) { const buildInfo = module.buildInfo; if (buildInfo) { if (cachedMemCache.buildInfo !== buildInfo) { // use a new one const memCache = new WeakTupleMap(); moduleMemCaches.set(module, memCache); affectedModules.add(module); cachedMemCache.buildInfo = buildInfo; cachedMemCache.references = computeReferences(module); cachedMemCache.memCache = memCache; statChanged++; } else if (!compareReferences(module, cachedMemCache.references)) { // use a new one const memCache = new WeakTupleMap(); moduleMemCaches.set(module, memCache); affectedModules.add(module); cachedMemCache.references = computeReferences(module); cachedMemCache.memCache = memCache; statReferencesChanged++; } else { // keep the old mem cache moduleMemCaches.set(module, cachedMemCache.memCache); statUnchanged++; } } else { infectedModules.add(module); moduleMemCacheCache.delete(module); statWithoutBuild++; } modulesWithoutCache.delete(module); } else { moduleMemCacheCache.delete(module); } } for (const module of modulesWithoutCache) { const buildInfo = module.buildInfo; if (buildInfo) { // create a new entry const memCache = new WeakTupleMap(); moduleMemCacheCache.set(module, { buildInfo, references: computeReferences(module), memCache }); moduleMemCaches.set(module, memCache); affectedModules.add(module); statNew++; } else { infectedModules.add(module); statWithoutBuild++; } } const reduceAffectType = connections => { let affected = false; for (const { dependency } of connections) { if (!dependency) continue; const type = dependency.couldAffectReferencingModule(); if (type === Dependency.TRANSITIVE) return Dependency.TRANSITIVE; if (type === false) continue; affected = true; } return affected; }; const directOnlyInfectedModules = new Set(); for (const module of infectedModules) { for (const [ referencingModule, connections ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) { if (!referencingModule) continue; if (infectedModules.has(referencingModule)) continue; const type = reduceAffectType(connections); if (!type) continue; if (type === true) { directOnlyInfectedModules.add(referencingModule); } else { infectedModules.add(referencingModule); } } } for (const module of directOnlyInfectedModules) infectedModules.add(module); const directOnlyAffectModules = new Set(); for (const module of affectedModules) { for (const [ referencingModule, connections ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) { if (!referencingModule) continue; if (infectedModules.has(referencingModule)) continue; if (affectedModules.has(referencingModule)) continue; const type = reduceAffectType(connections); if (!type) continue; if (type === true) { directOnlyAffectModules.add(referencingModule); } else { affectedModules.add(referencingModule); } const memCache = new WeakTupleMap(); const cache = moduleMemCacheCache.get(referencingModule); cache.memCache = memCache; moduleMemCaches.set(referencingModule, memCache); } } for (const module of directOnlyAffectModules) affectedModules.add(module); this.logger.log( `${Math.round( (100 * (affectedModules.size + infectedModules.size)) / this.modules.size )}% (${affectedModules.size} affected + ${ infectedModules.size } infected of ${ this.modules.size }) modules flagged as affected (${statNew} new modules, ${statChanged} changed, ${statReferencesChanged} references changed, ${statUnchanged} unchanged, ${statWithoutBuild} were not built)` ); } _computeAffectedModulesWithChunkGraph() { const { moduleMemCaches } = this; if (!moduleMemCaches) return; const moduleMemCaches2 = (this.moduleMemCaches2 = new Map()); const { moduleGraph, chunkGraph } = this; const key = "memCache2"; let statUnchanged = 0; let statChanged = 0; let statNew = 0; /** * @param {Module} module module * @returns {{ id: string | number, modules?: Map<Module, string | number | undefined>, blocks?: (string | number)[] }} references */ const computeReferences = module => { const id = chunkGraph.getModuleId(module); /** @type {Map<Module, string | number | undefined>} */ let modules = undefined; /** @type {(string | number)[] | undefined} */ let blocks = undefined; const outgoing = moduleGraph.getOutgoingConnectionsByModule(module); if (outgoing !== undefined) { for (const m of outgoing.keys()) { if (!m) continue; if (modules === undefined) modules = new Map(); modules.set(m, chunkGraph.getModuleId(m)); } } if (module.blocks.length > 0) { blocks = []; const queue = Array.from(module.blocks); for (const block of queue) { const chunkGroup = chunkGraph.getBlockChunkGroup(block); if (chunkGroup) { for (const chunk of chunkGroup.chunks) { blocks.push(chunk.id); } } else { blocks.push(null); } queue.push.apply(queue, block.blocks); } } return { id, modules, blocks }; }; /** * @param {Module} module module * @param {Object} references references * @param {string | number} references.id id * @param {Map<Module, string | number>=} references.modules modules * @param {(string | number)[]=} references.blocks blocks * @returns {boolean} ok? */ const compareReferences = (module, { id, modules, blocks }) => { if (id !== chunkGraph.getModuleId(module)) return false; if (modules !== undefined) { for (const [module, id] of modules) { if (chunkGraph.getModuleId(module) !== id) return false; } } if (blocks !== undefined) { const queue = Array.from(module.blocks); let i = 0; for (const block of queue) { const chunkGroup = chunkGraph.getBlockChunkGroup(block); if (chunkGroup) { for (const chunk of chunkGroup.chunks) { if (i >= blocks.length || blocks[i++] !== chunk.id) return false; } } else { if (i >= blocks.length || blocks[i++] !== null) return false; } queue.push.apply(queue, block.blocks); } if (i !== blocks.length) return false; } return true; }; for (const [module, memCache] of moduleMemCaches) { /** @type {{ references: { id: string | number, modules?: Map<Module, string | number | undefined>, blocks?: (string | number)[]}, memCache: WeakTupleMap<any[], any> }} */ const cache = memCache.get(key); if (cache === undefined) { const memCache2 = new WeakTupleMap(); memCache.set(key, { references: computeReferences(module), memCache: memCache2 }); moduleMemCaches2.set(module, memCache2); statNew++; } else if (!compareReferences(module, cache.references)) { const memCache = new WeakTupleMap(); cache.references = computeReferences(module); cache.memCache = memCache; moduleMemCaches2.set(module, memCache); statChanged++; } else { moduleMemCaches2.set(module, cache.memCache); statUnchanged++; } } this.logger.log( `${Math.round( (100 * statChanged) / (statNew + statChanged + statUnchanged) )}% modules flagged as affected by chunk graph (${statNew} new modules, ${statChanged} changed, ${statUnchanged} unchanged)` ); } finish(callback) { this.factorizeQueue.clear(); if (this.profile) { this.logger.time("finish module profiles"); const ParallelismFactorCalculator = require("./util/ParallelismFactorCalculator"); const p = new ParallelismFactorCalculator(); const moduleGraph = this.moduleGraph; const modulesWithProfiles = new Map(); for (const module of this.modules) { const profile = moduleGraph.getProfile(module); if (!profile) continue; modulesWithProfiles.set(module, profile); p.range( profile.buildingStartTime, profile.buildingEndTime, f => (profile.buildingParallelismFactor = f) ); p.range( profile.factoryStartTime, profile.factoryEndTime, f => (profile.factoryParallelismFactor = f) ); p.range( profile.integrationStartTime, profile.integrationEndTime, f => (profile.integrationParallelismFactor = f) ); p.range( profile.storingStartTime, profile.storingEndTime, f => (profile.storingParallelismFactor = f) ); p.range( profile.restoringStartTime, profile.restoringEndTime, f => (profile.restoringParallelismFactor = f) ); if (profile.additionalFactoryTimes) { for (const { start, end } of profile.additionalFactoryTimes) { const influence = (end - start) / profile.additionalFactories; p.range( start, end, f => (profile.additionalFactoriesParallelismFactor += f * influence) ); } } } p.calculate(); const logger = this.getLogger("webpack.Compilation.ModuleProfile"); const logByValue = (value, msg) => { if (value > 1000) { logger.error(msg); } else if (value > 500) { logger.warn(msg); } else if (value > 200) { logger.info(msg); } else if (value > 30) { logger.log(msg); } else { logger.debug(msg); } }; const logNormalSummary = (category, getDuration, getParallelism) => { let sum = 0; let max = 0; for (const [module, profile] of modulesWithProfiles) { const p = getParallelism(profile); const d = getDuration(profile); if (d === 0 || p === 0) continue; const t = d / p; sum += t; if (t <= 10) continue; logByValue( t, ` | ${Math.round(t)} ms${ p >= 1.1 ? ` (parallelism ${Math.round(p * 10) / 10})` : "" } ${category} > ${module.readableIdentifier(this.requestShortener)}` ); max = Math.max(max, t); } if (sum <= 10) return; logByValue( Math.max(sum / 10, max), `${Math.round(sum)} ms ${category}` ); }; const logByLoadersSummary = (category, getDuration, getParallelism) => { const map = new Map(); for (const [module, profile] of modulesWithProfiles) { const list = provide( map, module.type + "!" + module.identifier().replace(/(!|^)[^!]*$/, ""), () => [] ); list.push({ module, profile }); } let sum = 0; let max = 0; for (const [key, modules] of map) { let innerSum =
{'addition_count': 1, 'commit_subject': 'Merge pull request #11003 from resistdesign/patch-1', 'deletion_count': 1, 'file_extension': '.js', 'lang': 'js', 'license': 'mit', 'repo_name': 'webpack/webpack'}