UNPKG

159 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const asyncLib = require("neo-async");
9const {
10 HookMap,
11 SyncHook,
12 SyncBailHook,
13 SyncWaterfallHook,
14 AsyncSeriesHook,
15 AsyncSeriesBailHook,
16 AsyncParallelHook
17} = require("tapable");
18const util = require("util");
19const { CachedSource } = require("webpack-sources");
20const { MultiItemCache } = require("./CacheFacade");
21const Chunk = require("./Chunk");
22const ChunkGraph = require("./ChunkGraph");
23const ChunkGroup = require("./ChunkGroup");
24const ChunkRenderError = require("./ChunkRenderError");
25const ChunkTemplate = require("./ChunkTemplate");
26const CodeGenerationError = require("./CodeGenerationError");
27const CodeGenerationResults = require("./CodeGenerationResults");
28const Dependency = require("./Dependency");
29const DependencyTemplates = require("./DependencyTemplates");
30const Entrypoint = require("./Entrypoint");
31const ErrorHelpers = require("./ErrorHelpers");
32const FileSystemInfo = require("./FileSystemInfo");
33const {
34 connectChunkGroupAndChunk,
35 connectChunkGroupParentAndChild
36} = require("./GraphHelpers");
37const {
38 makeWebpackError,
39 tryRunOrWebpackError
40} = require("./HookWebpackError");
41const MainTemplate = require("./MainTemplate");
42const Module = require("./Module");
43const ModuleDependencyError = require("./ModuleDependencyError");
44const ModuleDependencyWarning = require("./ModuleDependencyWarning");
45const ModuleGraph = require("./ModuleGraph");
46const ModuleNotFoundError = require("./ModuleNotFoundError");
47const ModuleProfile = require("./ModuleProfile");
48const ModuleRestoreError = require("./ModuleRestoreError");
49const ModuleStoreError = require("./ModuleStoreError");
50const ModuleTemplate = require("./ModuleTemplate");
51const RuntimeGlobals = require("./RuntimeGlobals");
52const RuntimeTemplate = require("./RuntimeTemplate");
53const Stats = require("./Stats");
54const WebpackError = require("./WebpackError");
55const buildChunkGraph = require("./buildChunkGraph");
56const BuildCycleError = require("./errors/BuildCycleError");
57const { Logger, LogType } = require("./logging/Logger");
58const StatsFactory = require("./stats/StatsFactory");
59const StatsPrinter = require("./stats/StatsPrinter");
60const { equals: arrayEquals } = require("./util/ArrayHelpers");
61const AsyncQueue = require("./util/AsyncQueue");
62const LazySet = require("./util/LazySet");
63const { provide } = require("./util/MapHelpers");
64const WeakTupleMap = require("./util/WeakTupleMap");
65const { cachedCleverMerge } = require("./util/cleverMerge");
66const {
67 compareLocations,
68 concatComparators,
69 compareSelect,
70 compareIds,
71 compareStringsNumeric,
72 compareModulesByIdentifier
73} = require("./util/comparators");
74const createHash = require("./util/createHash");
75const {
76 arrayToSetDeprecation,
77 soonFrozenObjectDeprecation,
78 createFakeHook
79} = require("./util/deprecation");
80const processAsyncTree = require("./util/processAsyncTree");
81const { getRuntimeKey } = require("./util/runtime");
82const { isSourceEqual } = require("./util/source");
83
84/** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */
85/** @typedef {import("webpack-sources").Source} Source */
86/** @typedef {import("../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescription */
87/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
88/** @typedef {import("../declarations/WebpackOptions").StatsOptions} StatsOptions */
89/** @typedef {import("../declarations/WebpackOptions").WebpackPluginFunction} WebpackPluginFunction */
90/** @typedef {import("../declarations/WebpackOptions").WebpackPluginInstance} WebpackPluginInstance */
91/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
92/** @typedef {import("./Cache")} Cache */
93/** @typedef {import("./CacheFacade")} CacheFacade */
94/** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
95/** @typedef {import("./Compiler")} Compiler */
96/** @typedef {import("./Compiler").CompilationParams} CompilationParams */
97/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
98/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
99/** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */
100/** @typedef {import("./DependencyTemplate")} DependencyTemplate */
101/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
102/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
103/** @typedef {import("./ModuleFactory")} ModuleFactory */
104/** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
105/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
106/** @typedef {import("./RequestShortener")} RequestShortener */
107/** @typedef {import("./RuntimeModule")} RuntimeModule */
108/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
109/** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions */
110/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
111/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsError} StatsError */
112/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModule} StatsModule */
113/** @typedef {import("./util/Hash")} Hash */
114/** @template T @typedef {import("./util/deprecation").FakeHook<T>} FakeHook<T> */
115/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
116
117/**
118 * @callback Callback
119 * @param {WebpackError=} err
120 * @returns {void}
121 */
122
123/**
124 * @callback ModuleCallback
125 * @param {WebpackError=} err
126 * @param {Module=} result
127 * @returns {void}
128 */
129
130/**
131 * @callback ModuleFactoryResultCallback
132 * @param {WebpackError=} err
133 * @param {ModuleFactoryResult=} result
134 * @returns {void}
135 */
136
137/**
138 * @callback ModuleOrFactoryResultCallback
139 * @param {WebpackError=} err
140 * @param {Module | ModuleFactoryResult=} result
141 * @returns {void}
142 */
143
144/**
145 * @callback ExecuteModuleCallback
146 * @param {WebpackError=} err
147 * @param {ExecuteModuleResult=} result
148 * @returns {void}
149 */
150
151/**
152 * @callback DepBlockVarDependenciesCallback
153 * @param {Dependency} dependency
154 * @returns {any}
155 */
156
157/** @typedef {new (...args: any[]) => Dependency} DepConstructor */
158/** @typedef {Record<string, Source>} CompilationAssets */
159
160/**
161 * @typedef {Object} AvailableModulesChunkGroupMapping
162 * @property {ChunkGroup} chunkGroup
163 * @property {Set<Module>} availableModules
164 * @property {boolean} needCopy
165 */
166
167/**
168 * @typedef {Object} DependenciesBlockLike
169 * @property {Dependency[]} dependencies
170 * @property {AsyncDependenciesBlock[]} blocks
171 */
172
173/**
174 * @typedef {Object} ChunkPathData
175 * @property {string|number} id
176 * @property {string=} name
177 * @property {string} hash
178 * @property {function(number): string=} hashWithLength
179 * @property {(Record<string, string>)=} contentHash
180 * @property {(Record<string, (length: number) => string>)=} contentHashWithLength
181 */
182
183/**
184 * @typedef {Object} ChunkHashContext
185 * @property {RuntimeTemplate} runtimeTemplate the runtime template
186 * @property {ModuleGraph} moduleGraph the module graph
187 * @property {ChunkGraph} chunkGraph the chunk graph
188 */
189
190/**
191 * @typedef {Object} RuntimeRequirementsContext
192 * @property {ChunkGraph} chunkGraph the chunk graph
193 * @property {CodeGenerationResults} codeGenerationResults the code generation results
194 */
195
196/**
197 * @typedef {Object} ExecuteModuleOptions
198 * @property {EntryOptions=} entryOptions
199 */
200
201/**
202 * @typedef {Object} ExecuteModuleResult
203 * @property {any} exports
204 * @property {boolean} cacheable
205 * @property {Map<string, { source: Source, info: AssetInfo }>} assets
206 * @property {LazySet<string>} fileDependencies
207 * @property {LazySet<string>} contextDependencies
208 * @property {LazySet<string>} missingDependencies
209 * @property {LazySet<string>} buildDependencies
210 */
211
212/**
213 * @typedef {Object} ExecuteModuleArgument
214 * @property {Module} module
215 * @property {{ id: string, exports: any, loaded: boolean }=} moduleObject
216 * @property {any} preparedInfo
217 * @property {CodeGenerationResult} codeGenerationResult
218 */
219
220/**
221 * @typedef {Object} ExecuteModuleContext
222 * @property {Map<string, { source: Source, info: AssetInfo }>} assets
223 * @property {Chunk} chunk
224 * @property {ChunkGraph} chunkGraph
225 * @property {function(string): any=} __webpack_require__
226 */
227
228/**
229 * @typedef {Object} EntryData
230 * @property {Dependency[]} dependencies dependencies of the entrypoint that should be evaluated at startup
231 * @property {Dependency[]} includeDependencies dependencies of the entrypoint that should be included but not evaluated
232 * @property {EntryOptions} options options of the entrypoint
233 */
234
235/**
236 * @typedef {Object} LogEntry
237 * @property {string} type
238 * @property {any[]} args
239 * @property {number} time
240 * @property {string[]=} trace
241 */
242
243/**
244 * @typedef {Object} KnownAssetInfo
245 * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash)
246 * @property {boolean=} minimized whether the asset is minimized
247 * @property {string | string[]=} fullhash the value(s) of the full hash used for this asset
248 * @property {string | string[]=} chunkhash the value(s) of the chunk hash used for this asset
249 * @property {string | string[]=} modulehash the value(s) of the module hash used for this asset
250 * @property {string | string[]=} contenthash the value(s) of the content hash used for this asset
251 * @property {string=} sourceFilename when asset was created from a source file (potentially transformed), the original filename relative to compilation context
252 * @property {number=} size size in bytes, only set after asset has been emitted
253 * @property {boolean=} development true, when asset is only used for development and doesn't count towards user-facing assets
254 * @property {boolean=} hotModuleReplacement true, when asset ships data for updating an existing application (HMR)
255 * @property {boolean=} javascriptModule true, when asset is javascript and an ESM
256 * @property {Record<string, string | string[]>=} related object of pointers to other assets, keyed by type of relation (only points from parent to child)
257 */
258
259/** @typedef {KnownAssetInfo & Record<string, any>} AssetInfo */
260
261/**
262 * @typedef {Object} Asset
263 * @property {string} name the filename of the asset
264 * @property {Source} source source of the asset
265 * @property {AssetInfo} info info about the asset
266 */
267
268/**
269 * @typedef {Object} ModulePathData
270 * @property {string|number} id
271 * @property {string} hash
272 * @property {function(number): string=} hashWithLength
273 */
274
275/**
276 * @typedef {Object} PathData
277 * @property {ChunkGraph=} chunkGraph
278 * @property {string=} hash
279 * @property {function(number): string=} hashWithLength
280 * @property {(Chunk|ChunkPathData)=} chunk
281 * @property {(Module|ModulePathData)=} module
282 * @property {RuntimeSpec=} runtime
283 * @property {string=} filename
284 * @property {string=} basename
285 * @property {string=} query
286 * @property {string=} contentHashType
287 * @property {string=} contentHash
288 * @property {function(number): string=} contentHashWithLength
289 * @property {boolean=} noChunkHash
290 * @property {string=} url
291 */
292
293/**
294 * @typedef {Object} KnownNormalizedStatsOptions
295 * @property {string} context
296 * @property {RequestShortener} requestShortener
297 * @property {string} chunksSort
298 * @property {string} modulesSort
299 * @property {string} chunkModulesSort
300 * @property {string} nestedModulesSort
301 * @property {string} assetsSort
302 * @property {boolean} ids
303 * @property {boolean} cachedAssets
304 * @property {boolean} groupAssetsByEmitStatus
305 * @property {boolean} groupAssetsByPath
306 * @property {boolean} groupAssetsByExtension
307 * @property {number} assetsSpace
308 * @property {((value: string, asset: StatsAsset) => boolean)[]} excludeAssets
309 * @property {((name: string, module: StatsModule, type: "module" | "chunk" | "root-of-chunk" | "nested") => boolean)[]} excludeModules
310 * @property {((warning: StatsError, textValue: string) => boolean)[]} warningsFilter
311 * @property {boolean} cachedModules
312 * @property {boolean} orphanModules
313 * @property {boolean} dependentModules
314 * @property {boolean} runtimeModules
315 * @property {boolean} groupModulesByCacheStatus
316 * @property {boolean} groupModulesByLayer
317 * @property {boolean} groupModulesByAttributes
318 * @property {boolean} groupModulesByPath
319 * @property {boolean} groupModulesByExtension
320 * @property {boolean} groupModulesByType
321 * @property {boolean | "auto"} entrypoints
322 * @property {boolean} chunkGroups
323 * @property {boolean} chunkGroupAuxiliary
324 * @property {boolean} chunkGroupChildren
325 * @property {number} chunkGroupMaxAssets
326 * @property {number} modulesSpace
327 * @property {number} chunkModulesSpace
328 * @property {number} nestedModulesSpace
329 * @property {false|"none"|"error"|"warn"|"info"|"log"|"verbose"} logging
330 * @property {((value: string) => boolean)[]} loggingDebug
331 * @property {boolean} loggingTrace
332 * @property {any} _env
333 */
334
335/** @typedef {KnownNormalizedStatsOptions & Omit<StatsOptions, keyof KnownNormalizedStatsOptions> & Record<string, any>} NormalizedStatsOptions */
336
337/**
338 * @typedef {Object} KnownCreateStatsOptionsContext
339 * @property {boolean=} forToString
340 */
341
342/** @typedef {KnownCreateStatsOptionsContext & Record<string, any>} CreateStatsOptionsContext */
343
344/** @type {AssetInfo} */
345const EMPTY_ASSET_INFO = Object.freeze({});
346
347const esmDependencyCategory = "esm";
348// TODO webpack 6: remove
349const deprecatedNormalModuleLoaderHook = util.deprecate(
350 compilation => {
351 return require("./NormalModule").getCompilationHooks(compilation).loader;
352 },
353 "Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader",
354 "DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK"
355);
356
357// TODO webpack 6: remove
358const defineRemovedModuleTemplates = moduleTemplates => {
359 Object.defineProperties(moduleTemplates, {
360 asset: {
361 enumerable: false,
362 configurable: false,
363 get: () => {
364 throw new WebpackError(
365 "Compilation.moduleTemplates.asset has been removed"
366 );
367 }
368 },
369 webassembly: {
370 enumerable: false,
371 configurable: false,
372 get: () => {
373 throw new WebpackError(
374 "Compilation.moduleTemplates.webassembly has been removed"
375 );
376 }
377 }
378 });
379 moduleTemplates = undefined;
380};
381
382const byId = compareSelect(
383 /**
384 * @param {Chunk} c chunk
385 * @returns {number | string} id
386 */ c => c.id,
387 compareIds
388);
389
390const byNameOrHash = concatComparators(
391 compareSelect(
392 /**
393 * @param {Compilation} c compilation
394 * @returns {string} name
395 */
396 c => c.name,
397 compareIds
398 ),
399 compareSelect(
400 /**
401 * @param {Compilation} c compilation
402 * @returns {string} hash
403 */ c => c.fullHash,
404 compareIds
405 )
406);
407
408const byMessage = compareSelect(err => `${err.message}`, compareStringsNumeric);
409
410const byModule = compareSelect(
411 err => (err.module && err.module.identifier()) || "",
412 compareStringsNumeric
413);
414
415const byLocation = compareSelect(err => err.loc, compareLocations);
416
417const compareErrors = concatComparators(byModule, byLocation, byMessage);
418
419/** @type {WeakMap<Dependency, Module & { restoreFromUnsafeCache: Function } | null>} */
420const unsafeCacheDependencies = new WeakMap();
421
422/** @type {WeakMap<Module & { restoreFromUnsafeCache: Function }, object>} */
423const unsafeCacheData = new WeakMap();
424
425class Compilation {
426 /**
427 * Creates an instance of Compilation.
428 * @param {Compiler} compiler the compiler which created the compilation
429 * @param {CompilationParams} params the compilation parameters
430 */
431 constructor(compiler, params) {
432 this._backCompat = compiler._backCompat;
433
434 const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this);
435 /** @typedef {{ additionalAssets?: true | Function }} ProcessAssetsAdditionalOptions */
436 /** @type {AsyncSeriesHook<[CompilationAssets], ProcessAssetsAdditionalOptions>} */
437 const processAssetsHook = new AsyncSeriesHook(["assets"]);
438
439 let savedAssets = new Set();
440 const popNewAssets = assets => {
441 let newAssets = undefined;
442 for (const file of Object.keys(assets)) {
443 if (savedAssets.has(file)) continue;
444 if (newAssets === undefined) {
445 newAssets = Object.create(null);
446 }
447 newAssets[file] = assets[file];
448 savedAssets.add(file);
449 }
450 return newAssets;
451 };
452 processAssetsHook.intercept({
453 name: "Compilation",
454 call: () => {
455 savedAssets = new Set(Object.keys(this.assets));
456 },
457 register: tap => {
458 const { type, name } = tap;
459 const { fn, additionalAssets, ...remainingTap } = tap;
460 const additionalAssetsFn =
461 additionalAssets === true ? fn : additionalAssets;
462 const processedAssets = additionalAssetsFn ? new WeakSet() : undefined;
463 switch (type) {
464 case "sync":
465 if (additionalAssetsFn) {
466 this.hooks.processAdditionalAssets.tap(name, assets => {
467 if (processedAssets.has(this.assets))
468 additionalAssetsFn(assets);
469 });
470 }
471 return {
472 ...remainingTap,
473 type: "async",
474 fn: (assets, callback) => {
475 try {
476 fn(assets);
477 } catch (e) {
478 return callback(e);
479 }
480 if (processedAssets !== undefined)
481 processedAssets.add(this.assets);
482 const newAssets = popNewAssets(assets);
483 if (newAssets !== undefined) {
484 this.hooks.processAdditionalAssets.callAsync(
485 newAssets,
486 callback
487 );
488 return;
489 }
490 callback();
491 }
492 };
493 case "async":
494 if (additionalAssetsFn) {
495 this.hooks.processAdditionalAssets.tapAsync(
496 name,
497 (assets, callback) => {
498 if (processedAssets.has(this.assets))
499 return additionalAssetsFn(assets, callback);
500 callback();
501 }
502 );
503 }
504 return {
505 ...remainingTap,
506 fn: (assets, callback) => {
507 fn(assets, err => {
508 if (err) return callback(err);
509 if (processedAssets !== undefined)
510 processedAssets.add(this.assets);
511 const newAssets = popNewAssets(assets);
512 if (newAssets !== undefined) {
513 this.hooks.processAdditionalAssets.callAsync(
514 newAssets,
515 callback
516 );
517 return;
518 }
519 callback();
520 });
521 }
522 };
523 case "promise":
524 if (additionalAssetsFn) {
525 this.hooks.processAdditionalAssets.tapPromise(name, assets => {
526 if (processedAssets.has(this.assets))
527 return additionalAssetsFn(assets);
528 return Promise.resolve();
529 });
530 }
531 return {
532 ...remainingTap,
533 fn: assets => {
534 const p = fn(assets);
535 if (!p || !p.then) return p;
536 return p.then(() => {
537 if (processedAssets !== undefined)
538 processedAssets.add(this.assets);
539 const newAssets = popNewAssets(assets);
540 if (newAssets !== undefined) {
541 return this.hooks.processAdditionalAssets.promise(
542 newAssets
543 );
544 }
545 });
546 }
547 };
548 }
549 }
550 });
551
552 /** @type {SyncHook<[CompilationAssets]>} */
553 const afterProcessAssetsHook = new SyncHook(["assets"]);
554
555 /**
556 * @template T
557 * @param {string} name name of the hook
558 * @param {number} stage new stage
559 * @param {function(): AsArray<T>} getArgs get old hook function args
560 * @param {string=} code deprecation code (not deprecated when unset)
561 * @returns {FakeHook<Pick<AsyncSeriesHook<T>, "tap" | "tapAsync" | "tapPromise" | "name">>} fake hook which redirects
562 */
563 const createProcessAssetsHook = (name, stage, getArgs, code) => {
564 if (!this._backCompat && code) return undefined;
565 const errorMessage =
566 reason => `Can't automatically convert plugin using Compilation.hooks.${name} to Compilation.hooks.processAssets because ${reason}.
567BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a single Compilation.hooks.processAssets hook.`;
568 const getOptions = options => {
569 if (typeof options === "string") options = { name: options };
570 if (options.stage) {
571 throw new Error(errorMessage("it's using the 'stage' option"));
572 }
573 return { ...options, stage: stage };
574 };
575 return createFakeHook(
576 {
577 name,
578 /** @type {AsyncSeriesHook<T>["intercept"]} */
579 intercept(interceptor) {
580 throw new Error(errorMessage("it's using 'intercept'"));
581 },
582 /** @type {AsyncSeriesHook<T>["tap"]} */
583 tap: (options, fn) => {
584 processAssetsHook.tap(getOptions(options), () => fn(...getArgs()));
585 },
586 /** @type {AsyncSeriesHook<T>["tapAsync"]} */
587 tapAsync: (options, fn) => {
588 processAssetsHook.tapAsync(
589 getOptions(options),
590 (assets, callback) =>
591 /** @type {any} */ (fn)(...getArgs(), callback)
592 );
593 },
594 /** @type {AsyncSeriesHook<T>["tapPromise"]} */
595 tapPromise: (options, fn) => {
596 processAssetsHook.tapPromise(getOptions(options), () =>
597 fn(...getArgs())
598 );
599 }
600 },
601 `${name} is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)`,
602 code
603 );
604 };
605 this.hooks = Object.freeze({
606 /** @type {SyncHook<[Module]>} */
607 buildModule: new SyncHook(["module"]),
608 /** @type {SyncHook<[Module]>} */
609 rebuildModule: new SyncHook(["module"]),
610 /** @type {SyncHook<[Module, WebpackError]>} */
611 failedModule: new SyncHook(["module", "error"]),
612 /** @type {SyncHook<[Module]>} */
613 succeedModule: new SyncHook(["module"]),
614 /** @type {SyncHook<[Module]>} */
615 stillValidModule: new SyncHook(["module"]),
616
617 /** @type {SyncHook<[Dependency, EntryOptions]>} */
618 addEntry: new SyncHook(["entry", "options"]),
619 /** @type {SyncHook<[Dependency, EntryOptions, Error]>} */
620 failedEntry: new SyncHook(["entry", "options", "error"]),
621 /** @type {SyncHook<[Dependency, EntryOptions, Module]>} */
622 succeedEntry: new SyncHook(["entry", "options", "module"]),
623
624 /** @type {SyncWaterfallHook<[(string[] | ReferencedExport)[], Dependency, RuntimeSpec]>} */
625 dependencyReferencedExports: new SyncWaterfallHook([
626 "referencedExports",
627 "dependency",
628 "runtime"
629 ]),
630
631 /** @type {SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
632 executeModule: new SyncHook(["options", "context"]),
633 /** @type {AsyncParallelHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
634 prepareModuleExecution: new AsyncParallelHook(["options", "context"]),
635
636 /** @type {AsyncSeriesHook<[Iterable<Module>]>} */
637 finishModules: new AsyncSeriesHook(["modules"]),
638 /** @type {AsyncSeriesHook<[Module]>} */
639 finishRebuildingModule: new AsyncSeriesHook(["module"]),
640 /** @type {SyncHook<[]>} */
641 unseal: new SyncHook([]),
642 /** @type {SyncHook<[]>} */
643 seal: new SyncHook([]),
644
645 /** @type {SyncHook<[]>} */
646 beforeChunks: new SyncHook([]),
647 /** @type {SyncHook<[Iterable<Chunk>]>} */
648 afterChunks: new SyncHook(["chunks"]),
649
650 /** @type {SyncBailHook<[Iterable<Module>]>} */
651 optimizeDependencies: new SyncBailHook(["modules"]),
652 /** @type {SyncHook<[Iterable<Module>]>} */
653 afterOptimizeDependencies: new SyncHook(["modules"]),
654
655 /** @type {SyncHook<[]>} */
656 optimize: new SyncHook([]),
657 /** @type {SyncBailHook<[Iterable<Module>]>} */
658 optimizeModules: new SyncBailHook(["modules"]),
659 /** @type {SyncHook<[Iterable<Module>]>} */
660 afterOptimizeModules: new SyncHook(["modules"]),
661
662 /** @type {SyncBailHook<[Iterable<Chunk>, ChunkGroup[]]>} */
663 optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
664 /** @type {SyncHook<[Iterable<Chunk>, ChunkGroup[]]>} */
665 afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
666
667 /** @type {AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>} */
668 optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
669 /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
670 afterOptimizeTree: new SyncHook(["chunks", "modules"]),
671
672 /** @type {AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>]>} */
673 optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]),
674 /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
675 afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
676 /** @type {SyncBailHook<[], boolean>} */
677 shouldRecord: new SyncBailHook([]),
678
679 /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
680 additionalChunkRuntimeRequirements: new SyncHook([
681 "chunk",
682 "runtimeRequirements",
683 "context"
684 ]),
685 /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */
686 runtimeRequirementInChunk: new HookMap(
687 () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
688 ),
689 /** @type {SyncHook<[Module, Set<string>, RuntimeRequirementsContext]>} */
690 additionalModuleRuntimeRequirements: new SyncHook([
691 "module",
692 "runtimeRequirements",
693 "context"
694 ]),
695 /** @type {HookMap<SyncBailHook<[Module, Set<string>, RuntimeRequirementsContext]>>} */
696 runtimeRequirementInModule: new HookMap(
697 () => new SyncBailHook(["module", "runtimeRequirements", "context"])
698 ),
699 /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
700 additionalTreeRuntimeRequirements: new SyncHook([
701 "chunk",
702 "runtimeRequirements",
703 "context"
704 ]),
705 /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */
706 runtimeRequirementInTree: new HookMap(
707 () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
708 ),
709
710 /** @type {SyncHook<[RuntimeModule, Chunk]>} */
711 runtimeModule: new SyncHook(["module", "chunk"]),
712
713 /** @type {SyncHook<[Iterable<Module>, any]>} */
714 reviveModules: new SyncHook(["modules", "records"]),
715 /** @type {SyncHook<[Iterable<Module>]>} */
716 beforeModuleIds: new SyncHook(["modules"]),
717 /** @type {SyncHook<[Iterable<Module>]>} */
718 moduleIds: new SyncHook(["modules"]),
719 /** @type {SyncHook<[Iterable<Module>]>} */
720 optimizeModuleIds: new SyncHook(["modules"]),
721 /** @type {SyncHook<[Iterable<Module>]>} */
722 afterOptimizeModuleIds: new SyncHook(["modules"]),
723
724 /** @type {SyncHook<[Iterable<Chunk>, any]>} */
725 reviveChunks: new SyncHook(["chunks", "records"]),
726 /** @type {SyncHook<[Iterable<Chunk>]>} */
727 beforeChunkIds: new SyncHook(["chunks"]),
728 /** @type {SyncHook<[Iterable<Chunk>]>} */
729 chunkIds: new SyncHook(["chunks"]),
730 /** @type {SyncHook<[Iterable<Chunk>]>} */
731 optimizeChunkIds: new SyncHook(["chunks"]),
732 /** @type {SyncHook<[Iterable<Chunk>]>} */
733 afterOptimizeChunkIds: new SyncHook(["chunks"]),
734
735 /** @type {SyncHook<[Iterable<Module>, any]>} */
736 recordModules: new SyncHook(["modules", "records"]),
737 /** @type {SyncHook<[Iterable<Chunk>, any]>} */
738 recordChunks: new SyncHook(["chunks", "records"]),
739
740 /** @type {SyncHook<[Iterable<Module>]>} */
741 optimizeCodeGeneration: new SyncHook(["modules"]),
742
743 /** @type {SyncHook<[]>} */
744 beforeModuleHash: new SyncHook([]),
745 /** @type {SyncHook<[]>} */
746 afterModuleHash: new SyncHook([]),
747
748 /** @type {SyncHook<[]>} */
749 beforeCodeGeneration: new SyncHook([]),
750 /** @type {SyncHook<[]>} */
751 afterCodeGeneration: new SyncHook([]),
752
753 /** @type {SyncHook<[]>} */
754 beforeRuntimeRequirements: new SyncHook([]),
755 /** @type {SyncHook<[]>} */
756 afterRuntimeRequirements: new SyncHook([]),
757
758 /** @type {SyncHook<[]>} */
759 beforeHash: new SyncHook([]),
760 /** @type {SyncHook<[Chunk]>} */
761 contentHash: new SyncHook(["chunk"]),
762 /** @type {SyncHook<[]>} */
763 afterHash: new SyncHook([]),
764 /** @type {SyncHook<[any]>} */
765 recordHash: new SyncHook(["records"]),
766 /** @type {SyncHook<[Compilation, any]>} */
767 record: new SyncHook(["compilation", "records"]),
768
769 /** @type {SyncHook<[]>} */
770 beforeModuleAssets: new SyncHook([]),
771 /** @type {SyncBailHook<[], boolean>} */
772 shouldGenerateChunkAssets: new SyncBailHook([]),
773 /** @type {SyncHook<[]>} */
774 beforeChunkAssets: new SyncHook([]),
775 // TODO webpack 6 remove
776 /** @deprecated */
777 additionalChunkAssets: createProcessAssetsHook(
778 "additionalChunkAssets",
779 Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
780 () => [this.chunks],
781 "DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS"
782 ),
783
784 // TODO webpack 6 deprecate
785 /** @deprecated */
786 additionalAssets: createProcessAssetsHook(
787 "additionalAssets",
788 Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
789 () => []
790 ),
791 // TODO webpack 6 remove
792 /** @deprecated */
793 optimizeChunkAssets: createProcessAssetsHook(
794 "optimizeChunkAssets",
795 Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,
796 () => [this.chunks],
797 "DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS"
798 ),
799 // TODO webpack 6 remove
800 /** @deprecated */
801 afterOptimizeChunkAssets: createProcessAssetsHook(
802 "afterOptimizeChunkAssets",
803 Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1,
804 () => [this.chunks],
805 "DEP_WEBPACK_COMPILATION_AFTER_OPTIMIZE_CHUNK_ASSETS"
806 ),
807 // TODO webpack 6 deprecate
808 /** @deprecated */
809 optimizeAssets: processAssetsHook,
810 // TODO webpack 6 deprecate
811 /** @deprecated */
812 afterOptimizeAssets: afterProcessAssetsHook,
813
814 processAssets: processAssetsHook,
815 afterProcessAssets: afterProcessAssetsHook,
816 /** @type {AsyncSeriesHook<[CompilationAssets]>} */
817 processAdditionalAssets: new AsyncSeriesHook(["assets"]),
818
819 /** @type {SyncBailHook<[], boolean>} */
820 needAdditionalSeal: new SyncBailHook([]),
821 /** @type {AsyncSeriesHook<[]>} */
822 afterSeal: new AsyncSeriesHook([]),
823
824 /** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */
825 renderManifest: new SyncWaterfallHook(["result", "options"]),
826
827 /** @type {SyncHook<[Hash]>} */
828 fullHash: new SyncHook(["hash"]),
829 /** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */
830 chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]),
831
832 /** @type {SyncHook<[Module, string]>} */
833 moduleAsset: new SyncHook(["module", "filename"]),
834 /** @type {SyncHook<[Chunk, string]>} */
835 chunkAsset: new SyncHook(["chunk", "filename"]),
836
837 /** @type {SyncWaterfallHook<[string, object, AssetInfo]>} */
838 assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]),
839
840 /** @type {SyncBailHook<[], boolean>} */
841 needAdditionalPass: new SyncBailHook([]),
842
843 /** @type {SyncHook<[Compiler, string, number]>} */
844 childCompiler: new SyncHook([
845 "childCompiler",
846 "compilerName",
847 "compilerIndex"
848 ]),
849
850 /** @type {SyncBailHook<[string, LogEntry], true>} */
851 log: new SyncBailHook(["origin", "logEntry"]),
852
853 /** @type {SyncWaterfallHook<[WebpackError[]]>} */
854 processWarnings: new SyncWaterfallHook(["warnings"]),
855 /** @type {SyncWaterfallHook<[WebpackError[]]>} */
856 processErrors: new SyncWaterfallHook(["errors"]),
857
858 /** @type {HookMap<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>} */
859 statsPreset: new HookMap(() => new SyncHook(["options", "context"])),
860 /** @type {SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>} */
861 statsNormalize: new SyncHook(["options", "context"]),
862 /** @type {SyncHook<[StatsFactory, NormalizedStatsOptions]>} */
863 statsFactory: new SyncHook(["statsFactory", "options"]),
864 /** @type {SyncHook<[StatsPrinter, NormalizedStatsOptions]>} */
865 statsPrinter: new SyncHook(["statsPrinter", "options"]),
866
867 get normalModuleLoader() {
868 return getNormalModuleLoader();
869 }
870 });
871 /** @type {string=} */
872 this.name = undefined;
873 this.startTime = undefined;
874 this.endTime = undefined;
875 /** @type {Compiler} */
876 this.compiler = compiler;
877 this.resolverFactory = compiler.resolverFactory;
878 this.inputFileSystem = compiler.inputFileSystem;
879 this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, {
880 managedPaths: compiler.managedPaths,
881 immutablePaths: compiler.immutablePaths,
882 logger: this.getLogger("webpack.FileSystemInfo"),
883 hashFunction: compiler.options.output.hashFunction
884 });
885 if (compiler.fileTimestamps) {
886 this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
887 }
888 if (compiler.contextTimestamps) {
889 this.fileSystemInfo.addContextTimestamps(
890 compiler.contextTimestamps,
891 true
892 );
893 }
894 /** @type {Map<string, string | Set<string>>} */
895 this.valueCacheVersions = new Map();
896 this.requestShortener = compiler.requestShortener;
897 this.compilerPath = compiler.compilerPath;
898
899 this.logger = this.getLogger("webpack.Compilation");
900
901 const options = compiler.options;
902 this.options = options;
903 this.outputOptions = options && options.output;
904 /** @type {boolean} */
905 this.bail = (options && options.bail) || false;
906 /** @type {boolean} */
907 this.profile = (options && options.profile) || false;
908
909 this.params = params;
910 this.mainTemplate = new MainTemplate(this.outputOptions, this);
911 this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
912 this.runtimeTemplate = new RuntimeTemplate(
913 this,
914 this.outputOptions,
915 this.requestShortener
916 );
917 /** @type {{javascript: ModuleTemplate}} */
918 this.moduleTemplates = {
919 javascript: new ModuleTemplate(this.runtimeTemplate, this)
920 };
921 defineRemovedModuleTemplates(this.moduleTemplates);
922
923 /** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */
924 this.moduleMemCaches = undefined;
925 /** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */
926 this.moduleMemCaches2 = undefined;
927 this.moduleGraph = new ModuleGraph();
928 /** @type {ChunkGraph} */
929 this.chunkGraph = undefined;
930 /** @type {CodeGenerationResults} */
931 this.codeGenerationResults = undefined;
932
933 /** @type {AsyncQueue<Module, Module, Module>} */
934 this.processDependenciesQueue = new AsyncQueue({
935 name: "processDependencies",
936 parallelism: options.parallelism || 100,
937 processor: this._processModuleDependencies.bind(this)
938 });
939 /** @type {AsyncQueue<Module, string, Module>} */
940 this.addModuleQueue = new AsyncQueue({
941 name: "addModule",
942 parent: this.processDependenciesQueue,
943 getKey: module => module.identifier(),
944 processor: this._addModule.bind(this)
945 });
946 /** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */
947 this.factorizeQueue = new AsyncQueue({
948 name: "factorize",
949 parent: this.addModuleQueue,
950 processor: this._factorizeModule.bind(this)
951 });
952 /** @type {AsyncQueue<Module, Module, Module>} */
953 this.buildQueue = new AsyncQueue({
954 name: "build",
955 parent: this.factorizeQueue,
956 processor: this._buildModule.bind(this)
957 });
958 /** @type {AsyncQueue<Module, Module, Module>} */
959 this.rebuildQueue = new AsyncQueue({
960 name: "rebuild",
961 parallelism: options.parallelism || 100,
962 processor: this._rebuildModule.bind(this)
963 });
964
965 /**
966 * Modules in value are building during the build of Module in key.
967 * Means value blocking key from finishing.
968 * Needed to detect build cycles.
969 * @type {WeakMap<Module, Set<Module>>}
970 */
971 this.creatingModuleDuringBuild = new WeakMap();
972
973 /** @type {Map<string, EntryData>} */
974 this.entries = new Map();
975 /** @type {EntryData} */
976 this.globalEntry = {
977 dependencies: [],
978 includeDependencies: [],
979 options: {
980 name: undefined
981 }
982 };
983 /** @type {Map<string, Entrypoint>} */
984 this.entrypoints = new Map();
985 /** @type {Entrypoint[]} */
986 this.asyncEntrypoints = [];
987 /** @type {Set<Chunk>} */
988 this.chunks = new Set();
989 /** @type {ChunkGroup[]} */
990 this.chunkGroups = [];
991 /** @type {Map<string, ChunkGroup>} */
992 this.namedChunkGroups = new Map();
993 /** @type {Map<string, Chunk>} */
994 this.namedChunks = new Map();
995 /** @type {Set<Module>} */
996 this.modules = new Set();
997 if (this._backCompat) {
998 arrayToSetDeprecation(this.chunks, "Compilation.chunks");
999 arrayToSetDeprecation(this.modules, "Compilation.modules");
1000 }
1001 /** @private @type {Map<string, Module>} */
1002 this._modules = new Map();
1003 this.records = null;
1004 /** @type {string[]} */
1005 this.additionalChunkAssets = [];
1006 /** @type {CompilationAssets} */
1007 this.assets = {};
1008 /** @type {Map<string, AssetInfo>} */
1009 this.assetsInfo = new Map();
1010 /** @type {Map<string, Map<string, Set<string>>>} */
1011 this._assetsRelatedIn = new Map();
1012 /** @type {WebpackError[]} */
1013 this.errors = [];
1014 /** @type {WebpackError[]} */
1015 this.warnings = [];
1016 /** @type {Compilation[]} */
1017 this.children = [];
1018 /** @type {Map<string, LogEntry[]>} */
1019 this.logging = new Map();
1020 /** @type {Map<DepConstructor, ModuleFactory>} */
1021 this.dependencyFactories = new Map();
1022 /** @type {DependencyTemplates} */
1023 this.dependencyTemplates = new DependencyTemplates();
1024 this.childrenCounters = {};
1025 /** @type {Set<number|string>} */
1026 this.usedChunkIds = null;
1027 /** @type {Set<number>} */
1028 this.usedModuleIds = null;
1029 /** @type {boolean} */
1030 this.needAdditionalPass = false;
1031 /** @type {Set<Module & { restoreFromUnsafeCache: Function }>} */
1032 this._restoredUnsafeCacheModuleEntries = new Set();
1033 /** @type {Map<string, Module & { restoreFromUnsafeCache: Function }>} */
1034 this._restoredUnsafeCacheEntries = new Map();
1035 /** @type {WeakSet<Module>} */
1036 this.builtModules = new WeakSet();
1037 /** @type {WeakSet<Module>} */
1038 this.codeGeneratedModules = new WeakSet();
1039 /** @type {WeakSet<Module>} */
1040 this.buildTimeExecutedModules = new WeakSet();
1041 /** @private @type {Map<Module, Callback[]>} */
1042 this._rebuildingModules = new Map();
1043 /** @type {Set<string>} */
1044 this.emittedAssets = new Set();
1045 /** @type {Set<string>} */
1046 this.comparedForEmitAssets = new Set();
1047 /** @type {LazySet<string>} */
1048 this.fileDependencies = new LazySet();
1049 /** @type {LazySet<string>} */
1050 this.contextDependencies = new LazySet();
1051 /** @type {LazySet<string>} */
1052 this.missingDependencies = new LazySet();
1053 /** @type {LazySet<string>} */
1054 this.buildDependencies = new LazySet();
1055 // TODO webpack 6 remove
1056 this.compilationDependencies = {
1057 add: util.deprecate(
1058 item => this.fileDependencies.add(item),
1059 "Compilation.compilationDependencies is deprecated (used Compilation.fileDependencies instead)",
1060 "DEP_WEBPACK_COMPILATION_COMPILATION_DEPENDENCIES"
1061 )
1062 };
1063
1064 this._modulesCache = this.getCache("Compilation/modules");
1065 this._assetsCache = this.getCache("Compilation/assets");
1066 this._codeGenerationCache = this.getCache("Compilation/codeGeneration");
1067
1068 const unsafeCache = options.module.unsafeCache;
1069 this._unsafeCache = !!unsafeCache;
1070 this._unsafeCachePredicate =
1071 typeof unsafeCache === "function" ? unsafeCache : () => true;
1072 }
1073
1074 getStats() {
1075 return new Stats(this);
1076 }
1077
1078 /**
1079 * @param {StatsOptions | string} optionsOrPreset stats option value
1080 * @param {CreateStatsOptionsContext} context context
1081 * @returns {NormalizedStatsOptions} normalized options
1082 */
1083 createStatsOptions(optionsOrPreset, context = {}) {
1084 if (
1085 typeof optionsOrPreset === "boolean" ||
1086 typeof optionsOrPreset === "string"
1087 ) {
1088 optionsOrPreset = { preset: optionsOrPreset };
1089 }
1090 if (typeof optionsOrPreset === "object" && optionsOrPreset !== null) {
1091 // We use this method of shallow cloning this object to include
1092 // properties in the prototype chain
1093 /** @type {Partial<NormalizedStatsOptions>} */
1094 const options = {};
1095 for (const key in optionsOrPreset) {
1096 options[key] = optionsOrPreset[key];
1097 }
1098 if (options.preset !== undefined) {
1099 this.hooks.statsPreset.for(options.preset).call(options, context);
1100 }
1101 this.hooks.statsNormalize.call(options, context);
1102 return /** @type {NormalizedStatsOptions} */ (options);
1103 } else {
1104 /** @type {Partial<NormalizedStatsOptions>} */
1105 const options = {};
1106 this.hooks.statsNormalize.call(options, context);
1107 return /** @type {NormalizedStatsOptions} */ (options);
1108 }
1109 }
1110
1111 createStatsFactory(options) {
1112 const statsFactory = new StatsFactory();
1113 this.hooks.statsFactory.call(statsFactory, options);
1114 return statsFactory;
1115 }
1116
1117 createStatsPrinter(options) {
1118 const statsPrinter = new StatsPrinter();
1119 this.hooks.statsPrinter.call(statsPrinter, options);
1120 return statsPrinter;
1121 }
1122
1123 /**
1124 * @param {string} name cache name
1125 * @returns {CacheFacade} the cache facade instance
1126 */
1127 getCache(name) {
1128 return this.compiler.getCache(name);
1129 }
1130
1131 /**
1132 * @param {string | (function(): string)} name name of the logger, or function called once to get the logger name
1133 * @returns {Logger} a logger with that name
1134 */
1135 getLogger(name) {
1136 if (!name) {
1137 throw new TypeError("Compilation.getLogger(name) called without a name");
1138 }
1139 /** @type {LogEntry[] | undefined} */
1140 let logEntries;
1141 return new Logger(
1142 (type, args) => {
1143 if (typeof name === "function") {
1144 name = name();
1145 if (!name) {
1146 throw new TypeError(
1147 "Compilation.getLogger(name) called with a function not returning a name"
1148 );
1149 }
1150 }
1151 let trace;
1152 switch (type) {
1153 case LogType.warn:
1154 case LogType.error:
1155 case LogType.trace:
1156 trace = ErrorHelpers.cutOffLoaderExecution(new Error("Trace").stack)
1157 .split("\n")
1158 .slice(3);
1159 break;
1160 }
1161 /** @type {LogEntry} */
1162 const logEntry = {
1163 time: Date.now(),
1164 type,
1165 args,
1166 trace
1167 };
1168 if (this.hooks.log.call(name, logEntry) === undefined) {
1169 if (logEntry.type === LogType.profileEnd) {
1170 // eslint-disable-next-line node/no-unsupported-features/node-builtins
1171 if (typeof console.profileEnd === "function") {
1172 // eslint-disable-next-line node/no-unsupported-features/node-builtins
1173 console.profileEnd(`[${name}] ${logEntry.args[0]}`);
1174 }
1175 }
1176 if (logEntries === undefined) {
1177 logEntries = this.logging.get(name);
1178 if (logEntries === undefined) {
1179 logEntries = [];
1180 this.logging.set(name, logEntries);
1181 }
1182 }
1183 logEntries.push(logEntry);
1184 if (logEntry.type === LogType.profile) {
1185 // eslint-disable-next-line node/no-unsupported-features/node-builtins
1186 if (typeof console.profile === "function") {
1187 // eslint-disable-next-line node/no-unsupported-features/node-builtins
1188 console.profile(`[${name}] ${logEntry.args[0]}`);
1189 }
1190 }
1191 }
1192 },
1193 childName => {
1194 if (typeof name === "function") {
1195 if (typeof childName === "function") {
1196 return this.getLogger(() => {
1197 if (typeof name === "function") {
1198 name = name();
1199 if (!name) {
1200 throw new TypeError(
1201 "Compilation.getLogger(name) called with a function not returning a name"
1202 );
1203 }
1204 }
1205 if (typeof childName === "function") {
1206 childName = childName();
1207 if (!childName) {
1208 throw new TypeError(
1209 "Logger.getChildLogger(name) called with a function not returning a name"
1210 );
1211 }
1212 }
1213 return `${name}/${childName}`;
1214 });
1215 } else {
1216 return this.getLogger(() => {
1217 if (typeof name === "function") {
1218 name = name();
1219 if (!name) {
1220 throw new TypeError(
1221 "Compilation.getLogger(name) called with a function not returning a name"
1222 );
1223 }
1224 }
1225 return `${name}/${childName}`;
1226 });
1227 }
1228 } else {
1229 if (typeof childName === "function") {
1230 return this.getLogger(() => {
1231 if (typeof childName === "function") {
1232 childName = childName();
1233 if (!childName) {
1234 throw new TypeError(
1235 "Logger.getChildLogger(name) called with a function not returning a name"
1236 );
1237 }
1238 }
1239 return `${name}/${childName}`;
1240 });
1241 } else {
1242 return this.getLogger(`${name}/${childName}`);
1243 }
1244 }
1245 }
1246 );
1247 }
1248
1249 /**
1250 * @param {Module} module module to be added that was created
1251 * @param {ModuleCallback} callback returns the module in the compilation,
1252 * it could be the passed one (if new), or an already existing in the compilation
1253 * @returns {void}
1254 */
1255 addModule(module, callback) {
1256 this.addModuleQueue.add(module, callback);
1257 }
1258
1259 /**
1260 * @param {Module} module module to be added that was created
1261 * @param {ModuleCallback} callback returns the module in the compilation,
1262 * it could be the passed one (if new), or an already existing in the compilation
1263 * @returns {void}
1264 */
1265 _addModule(module, callback) {
1266 const identifier = module.identifier();
1267 const alreadyAddedModule = this._modules.get(identifier);
1268 if (alreadyAddedModule) {
1269 return callback(null, alreadyAddedModule);
1270 }
1271
1272 const currentProfile = this.profile
1273 ? this.moduleGraph.getProfile(module)
1274 : undefined;
1275 if (currentProfile !== undefined) {
1276 currentProfile.markRestoringStart();
1277 }
1278
1279 this._modulesCache.get(identifier, null, (err, cacheModule) => {
1280 if (err) return callback(new ModuleRestoreError(module, err));
1281
1282 if (currentProfile !== undefined) {
1283 currentProfile.markRestoringEnd();
1284 currentProfile.markIntegrationStart();
1285 }
1286
1287 if (cacheModule) {
1288 cacheModule.updateCacheModule(module);
1289
1290 module = cacheModule;
1291 }
1292 this._modules.set(identifier, module);
1293 this.modules.add(module);
1294 if (this._backCompat)
1295 ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
1296 if (currentProfile !== undefined) {
1297 currentProfile.markIntegrationEnd();
1298 }
1299 callback(null, module);
1300 });
1301 }
1302
1303 /**
1304 * Fetches a module from a compilation by its identifier
1305 * @param {Module} module the module provided
1306 * @returns {Module} the module requested
1307 */
1308 getModule(module) {
1309 const identifier = module.identifier();
1310 return this._modules.get(identifier);
1311 }
1312
1313 /**
1314 * Attempts to search for a module by its identifier
1315 * @param {string} identifier identifier (usually path) for module
1316 * @returns {Module|undefined} attempt to search for module and return it, else undefined
1317 */
1318 findModule(identifier) {
1319 return this._modules.get(identifier);
1320 }
1321
1322 /**
1323 * Schedules a build of the module object
1324 *
1325 * @param {Module} module module to be built
1326 * @param {ModuleCallback} callback the callback
1327 * @returns {void}
1328 */
1329 buildModule(module, callback) {
1330 this.buildQueue.add(module, callback);
1331 }
1332
1333 /**
1334 * Builds the module object
1335 *
1336 * @param {Module} module module to be built
1337 * @param {ModuleCallback} callback the callback
1338 * @returns {void}
1339 */
1340 _buildModule(module, callback) {
1341 const currentProfile = this.profile
1342 ? this.moduleGraph.getProfile(module)
1343 : undefined;
1344 if (currentProfile !== undefined) {
1345 currentProfile.markBuildingStart();
1346 }
1347
1348 module.needBuild(
1349 {
1350 compilation: this,
1351 fileSystemInfo: this.fileSystemInfo,
1352 valueCacheVersions: this.valueCacheVersions
1353 },
1354 (err, needBuild) => {
1355 if (err) return callback(err);
1356
1357 if (!needBuild) {
1358 if (currentProfile !== undefined) {
1359 currentProfile.markBuildingEnd();
1360 }
1361 this.hooks.stillValidModule.call(module);
1362 return callback();
1363 }
1364
1365 this.hooks.buildModule.call(module);
1366 this.builtModules.add(module);
1367 module.build(
1368 this.options,
1369 this,
1370 this.resolverFactory.get("normal", module.resolveOptions),
1371 this.inputFileSystem,
1372 err => {
1373 if (currentProfile !== undefined) {
1374 currentProfile.markBuildingEnd();
1375 }
1376 if (err) {
1377 this.hooks.failedModule.call(module, err);
1378 return callback(err);
1379 }
1380 if (currentProfile !== undefined) {
1381 currentProfile.markStoringStart();
1382 }
1383 this._modulesCache.store(module.identifier(), null, module, err => {
1384 if (currentProfile !== undefined) {
1385 currentProfile.markStoringEnd();
1386 }
1387 if (err) {
1388 this.hooks.failedModule.call(module, err);
1389 return callback(new ModuleStoreError(module, err));
1390 }
1391 this.hooks.succeedModule.call(module);
1392 return callback();
1393 });
1394 }
1395 );
1396 }
1397 );
1398 }
1399
1400 /**
1401 * @param {Module} module to be processed for deps
1402 * @param {ModuleCallback} callback callback to be triggered
1403 * @returns {void}
1404 */
1405 processModuleDependencies(module, callback) {
1406 this.processDependenciesQueue.add(module, callback);
1407 }
1408
1409 /**
1410 * @param {Module} module to be processed for deps
1411 * @returns {void}
1412 */
1413 processModuleDependenciesNonRecursive(module) {
1414 const processDependenciesBlock = block => {
1415 if (block.dependencies) {
1416 let i = 0;
1417 for (const dep of block.dependencies) {
1418 this.moduleGraph.setParents(dep, block, module, i++);
1419 }
1420 }
1421 if (block.blocks) {
1422 for (const b of block.blocks) processDependenciesBlock(b);
1423 }
1424 };
1425
1426 processDependenciesBlock(module);
1427 }
1428
1429 /**
1430 * @param {Module} module to be processed for deps
1431 * @param {ModuleCallback} callback callback to be triggered
1432 * @returns {void}
1433 */
1434 _processModuleDependencies(module, callback) {
1435 /** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], originModule: Module|null}>} */
1436 const sortedDependencies = [];
1437
1438 /** @type {DependenciesBlock} */
1439 let currentBlock;
1440
1441 /** @type {Map<ModuleFactory, Map<string, Dependency[]>>} */
1442 let dependencies;
1443 /** @type {DepConstructor} */
1444 let factoryCacheKey;
1445 /** @type {ModuleFactory} */
1446 let factoryCacheKey2;
1447 /** @type {Map<string, Dependency[]>} */
1448 let factoryCacheValue;
1449 /** @type {string} */
1450 let listCacheKey1;
1451 /** @type {string} */
1452 let listCacheKey2;
1453 /** @type {Dependency[]} */
1454 let listCacheValue;
1455
1456 let inProgressSorting = 1;
1457 let inProgressTransitive = 1;
1458
1459 const onDependenciesSorted = err => {
1460 if (err) return callback(err);
1461
1462 // early exit without changing parallelism back and forth
1463 if (sortedDependencies.length === 0 && inProgressTransitive === 1) {
1464 return callback();
1465 }
1466
1467 // This is nested so we need to allow one additional task
1468 this.processDependenciesQueue.increaseParallelism();
1469
1470 for (const item of sortedDependencies) {
1471 inProgressTransitive++;
1472 this.handleModuleCreation(item, err => {
1473 // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
1474 // errors are created inside closures that keep a reference to the Compilation, so errors are
1475 // leaking the Compilation object.
1476 if (err && this.bail) {
1477 if (inProgressTransitive <= 0) return;
1478 inProgressTransitive = -1;
1479 // eslint-disable-next-line no-self-assign
1480 err.stack = err.stack;
1481 onTransitiveTasksFinished(err);
1482 return;
1483 }
1484 if (--inProgressTransitive === 0) onTransitiveTasksFinished();
1485 });
1486 }
1487 if (--inProgressTransitive === 0) onTransitiveTasksFinished();
1488 };
1489
1490 const onTransitiveTasksFinished = err => {
1491 if (err) return callback(err);
1492 this.processDependenciesQueue.decreaseParallelism();
1493
1494 return callback();
1495 };
1496
1497 /**
1498 * @param {Dependency} dep dependency
1499 * @param {number} index index in block
1500 * @returns {void}
1501 */
1502 const processDependency = (dep, index) => {
1503 this.moduleGraph.setParents(dep, currentBlock, module, index);
1504 if (this._unsafeCache) {
1505 try {
1506 const unsafeCachedModule = unsafeCacheDependencies.get(dep);
1507 if (unsafeCachedModule === null) return;
1508 if (unsafeCachedModule !== undefined) {
1509 if (
1510 this._restoredUnsafeCacheModuleEntries.has(unsafeCachedModule)
1511 ) {
1512 this._handleExistingModuleFromUnsafeCache(
1513 module,
1514 dep,
1515 unsafeCachedModule
1516 );
1517 return;
1518 }
1519 const identifier = unsafeCachedModule.identifier();
1520 const cachedModule =
1521 this._restoredUnsafeCacheEntries.get(identifier);
1522 if (cachedModule !== undefined) {
1523 // update unsafe cache to new module
1524 unsafeCacheDependencies.set(dep, cachedModule);
1525 this._handleExistingModuleFromUnsafeCache(
1526 module,
1527 dep,
1528 cachedModule
1529 );
1530 return;
1531 }
1532 inProgressSorting++;
1533 this._modulesCache.get(identifier, null, (err, cachedModule) => {
1534 if (err) {
1535 if (inProgressSorting <= 0) return;
1536 inProgressSorting = -1;
1537 onDependenciesSorted(err);
1538 return;
1539 }
1540 try {
1541 if (!this._restoredUnsafeCacheEntries.has(identifier)) {
1542 const data = unsafeCacheData.get(cachedModule);
1543 if (data === undefined) {
1544 processDependencyForResolving(dep);
1545 if (--inProgressSorting === 0) onDependenciesSorted();
1546 return;
1547 }
1548 if (cachedModule !== unsafeCachedModule) {
1549 unsafeCacheDependencies.set(dep, cachedModule);
1550 }
1551 cachedModule.restoreFromUnsafeCache(
1552 data,
1553 this.params.normalModuleFactory,
1554 this.params
1555 );
1556 this._restoredUnsafeCacheEntries.set(
1557 identifier,
1558 cachedModule
1559 );
1560 this._restoredUnsafeCacheModuleEntries.add(cachedModule);
1561 if (!this.modules.has(cachedModule)) {
1562 inProgressTransitive++;
1563 this._handleNewModuleFromUnsafeCache(
1564 module,
1565 dep,
1566 cachedModule,
1567 err => {
1568 if (err) {
1569 if (inProgressTransitive <= 0) return;
1570 inProgressTransitive = -1;
1571 onTransitiveTasksFinished(err);
1572 }
1573 if (--inProgressTransitive === 0)
1574 return onTransitiveTasksFinished();
1575 }
1576 );
1577 if (--inProgressSorting === 0) onDependenciesSorted();
1578 return;
1579 }
1580 }
1581 if (unsafeCachedModule !== cachedModule) {
1582 unsafeCacheDependencies.set(dep, cachedModule);
1583 }
1584 this._handleExistingModuleFromUnsafeCache(
1585 module,
1586 dep,
1587 cachedModule
1588 ); // a3
1589 } catch (err) {
1590 if (inProgressSorting <= 0) return;
1591 inProgressSorting = -1;
1592 onDependenciesSorted(err);
1593 return;
1594 }
1595 if (--inProgressSorting === 0) onDependenciesSorted();
1596 });
1597 return;
1598 }
1599 } catch (e) {
1600 console.error(e);
1601 }
1602 }
1603 processDependencyForResolving(dep);
1604 };
1605
1606 /**
1607 * @param {Dependency} dep dependency
1608 * @returns {void}
1609 */
1610 const processDependencyForResolving = dep => {
1611 const resourceIdent = dep.getResourceIdentifier();
1612 if (resourceIdent !== undefined && resourceIdent !== null) {
1613 const category = dep.category;
1614 const constructor = /** @type {DepConstructor} */ (dep.constructor);
1615 if (factoryCacheKey === constructor) {
1616 // Fast path 1: same constructor as prev item
1617 if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
1618 // Super fast path 1: also same resource
1619 listCacheValue.push(dep);
1620 return;
1621 }
1622 } else {
1623 const factory = this.dependencyFactories.get(constructor);
1624 if (factory === undefined) {
1625 throw new Error(
1626 `No module factory available for dependency type: ${constructor.name}`
1627 );
1628 }
1629 if (factoryCacheKey2 === factory) {
1630 // Fast path 2: same factory as prev item
1631 factoryCacheKey = constructor;
1632 if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
1633 // Super fast path 2: also same resource
1634 listCacheValue.push(dep);
1635 return;
1636 }
1637 } else {
1638 // Slow path
1639 if (factoryCacheKey2 !== undefined) {
1640 // Archive last cache entry
1641 if (dependencies === undefined) dependencies = new Map();
1642 dependencies.set(factoryCacheKey2, factoryCacheValue);
1643 factoryCacheValue = dependencies.get(factory);
1644 if (factoryCacheValue === undefined) {
1645 factoryCacheValue = new Map();
1646 }
1647 } else {
1648 factoryCacheValue = new Map();
1649 }
1650 factoryCacheKey = constructor;
1651 factoryCacheKey2 = factory;
1652 }
1653 }
1654 // Here webpack is using heuristic that assumes
1655 // mostly esm dependencies would be used
1656 // so we don't allocate extra string for them
1657 const cacheKey =
1658 category === esmDependencyCategory
1659 ? resourceIdent
1660 : `${category}${resourceIdent}`;
1661 let list = factoryCacheValue.get(cacheKey);
1662 if (list === undefined) {
1663 factoryCacheValue.set(cacheKey, (list = []));
1664 sortedDependencies.push({
1665 factory: factoryCacheKey2,
1666 dependencies: list,
1667 originModule: module
1668 });
1669 }
1670 list.push(dep);
1671 listCacheKey1 = category;
1672 listCacheKey2 = resourceIdent;
1673 listCacheValue = list;
1674 }
1675 };
1676
1677 try {
1678 /** @type {DependenciesBlock[]} */
1679 const queue = [module];
1680 do {
1681 const block = queue.pop();
1682 if (block.dependencies) {
1683 currentBlock = block;
1684 let i = 0;
1685 for (const dep of block.dependencies) processDependency(dep, i++);
1686 }
1687 if (block.blocks) {
1688 for (const b of block.blocks) queue.push(b);
1689 }
1690 } while (queue.length !== 0);
1691 } catch (e) {
1692 return callback(e);
1693 }
1694
1695 if (--inProgressSorting === 0) onDependenciesSorted();
1696 }
1697
1698 _handleNewModuleFromUnsafeCache(originModule, dependency, module, callback) {
1699 const moduleGraph = this.moduleGraph;
1700
1701 moduleGraph.setResolvedModule(originModule, dependency, module);
1702
1703 moduleGraph.setIssuerIfUnset(
1704 module,
1705 originModule !== undefined ? originModule : null
1706 );
1707
1708 this._modules.set(module.identifier(), module);
1709 this.modules.add(module);
1710 if (this._backCompat)
1711 ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
1712
1713 this._handleModuleBuildAndDependencies(
1714 originModule,
1715 module,
1716 true,
1717 callback
1718 );
1719 }
1720
1721 _handleExistingModuleFromUnsafeCache(originModule, dependency, module) {
1722 const moduleGraph = this.moduleGraph;
1723
1724 moduleGraph.setResolvedModule(originModule, dependency, module);
1725 }
1726
1727 /**
1728 * @typedef {Object} HandleModuleCreationOptions
1729 * @property {ModuleFactory} factory
1730 * @property {Dependency[]} dependencies
1731 * @property {Module | null} originModule
1732 * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
1733 * @property {string=} context
1734 * @property {boolean=} recursive recurse into dependencies of the created module
1735 * @property {boolean=} connectOrigin connect the resolved module with the origin module
1736 */
1737
1738 /**
1739 * @param {HandleModuleCreationOptions} options options object
1740 * @param {ModuleCallback} callback callback
1741 * @returns {void}
1742 */
1743 handleModuleCreation(
1744 {
1745 factory,
1746 dependencies,
1747 originModule,
1748 contextInfo,
1749 context,
1750 recursive = true,
1751 connectOrigin = recursive
1752 },
1753 callback
1754 ) {
1755 const moduleGraph = this.moduleGraph;
1756
1757 const currentProfile = this.profile ? new ModuleProfile() : undefined;
1758
1759 this.factorizeModule(
1760 {
1761 currentProfile,
1762 factory,
1763 dependencies,
1764 factoryResult: true,
1765 originModule,
1766 contextInfo,
1767 context
1768 },
1769 (err, factoryResult) => {
1770 const applyFactoryResultDependencies = () => {
1771 const { fileDependencies, contextDependencies, missingDependencies } =
1772 factoryResult;
1773 if (fileDependencies) {
1774 this.fileDependencies.addAll(fileDependencies);
1775 }
1776 if (contextDependencies) {
1777 this.contextDependencies.addAll(contextDependencies);
1778 }
1779 if (missingDependencies) {
1780 this.missingDependencies.addAll(missingDependencies);
1781 }
1782 };
1783 if (err) {
1784 if (factoryResult) applyFactoryResultDependencies();
1785 if (dependencies.every(d => d.optional)) {
1786 this.warnings.push(err);
1787 return callback();
1788 } else {
1789 this.errors.push(err);
1790 return callback(err);
1791 }
1792 }
1793
1794 const newModule = factoryResult.module;
1795
1796 if (!newModule) {
1797 applyFactoryResultDependencies();
1798 return callback();
1799 }
1800
1801 if (currentProfile !== undefined) {
1802 moduleGraph.setProfile(newModule, currentProfile);
1803 }
1804
1805 this.addModule(newModule, (err, module) => {
1806 if (err) {
1807 applyFactoryResultDependencies();
1808 if (!err.module) {
1809 err.module = module;
1810 }
1811 this.errors.push(err);
1812
1813 return callback(err);
1814 }
1815
1816 if (
1817 this._unsafeCache &&
1818 factoryResult.cacheable !== false &&
1819 /** @type {any} */ (module).restoreFromUnsafeCache &&
1820 this._unsafeCachePredicate(module)
1821 ) {
1822 const unsafeCacheableModule =
1823 /** @type {Module & { restoreFromUnsafeCache: Function }} */ (
1824 module
1825 );
1826 for (let i = 0; i < dependencies.length; i++) {
1827 const dependency = dependencies[i];
1828 moduleGraph.setResolvedModule(
1829 connectOrigin ? originModule : null,
1830 dependency,
1831 unsafeCacheableModule
1832 );
1833 unsafeCacheDependencies.set(dependency, unsafeCacheableModule);
1834 }
1835 if (!unsafeCacheData.has(unsafeCacheableModule)) {
1836 unsafeCacheData.set(
1837 unsafeCacheableModule,
1838 unsafeCacheableModule.getUnsafeCacheData()
1839 );
1840 }
1841 } else {
1842 applyFactoryResultDependencies();
1843 for (let i = 0; i < dependencies.length; i++) {
1844 const dependency = dependencies[i];
1845 moduleGraph.setResolvedModule(
1846 connectOrigin ? originModule : null,
1847 dependency,
1848 module
1849 );
1850 }
1851 }
1852
1853 moduleGraph.setIssuerIfUnset(
1854 module,
1855 originModule !== undefined ? originModule : null
1856 );
1857 if (module !== newModule) {
1858 if (currentProfile !== undefined) {
1859 const otherProfile = moduleGraph.getProfile(module);
1860 if (otherProfile !== undefined) {
1861 currentProfile.mergeInto(otherProfile);
1862 } else {
1863 moduleGraph.setProfile(module, currentProfile);
1864 }
1865 }
1866 }
1867
1868 this._handleModuleBuildAndDependencies(
1869 originModule,
1870 module,
1871 recursive,
1872 callback
1873 );
1874 });
1875 }
1876 );
1877 }
1878
1879 _handleModuleBuildAndDependencies(originModule, module, recursive, callback) {
1880 // Check for cycles when build is trigger inside another build
1881 let creatingModuleDuringBuildSet = undefined;
1882 if (!recursive && this.buildQueue.isProcessing(originModule)) {
1883 // Track build dependency
1884 creatingModuleDuringBuildSet =
1885 this.creatingModuleDuringBuild.get(originModule);
1886 if (creatingModuleDuringBuildSet === undefined) {
1887 creatingModuleDuringBuildSet = new Set();
1888 this.creatingModuleDuringBuild.set(
1889 originModule,
1890 creatingModuleDuringBuildSet
1891 );
1892 }
1893 creatingModuleDuringBuildSet.add(module);
1894
1895 // When building is blocked by another module
1896 // search for a cycle, cancel the cycle by throwing
1897 // an error (otherwise this would deadlock)
1898 const blockReasons = this.creatingModuleDuringBuild.get(module);
1899 if (blockReasons !== undefined) {
1900 const set = new Set(blockReasons);
1901 for (const item of set) {
1902 const blockReasons = this.creatingModuleDuringBuild.get(item);
1903 if (blockReasons !== undefined) {
1904 for (const m of blockReasons) {
1905 if (m === module) {
1906 return callback(new BuildCycleError(module));
1907 }
1908 set.add(m);
1909 }
1910 }
1911 }
1912 }
1913 }
1914
1915 this.buildModule(module, err => {
1916 if (creatingModuleDuringBuildSet !== undefined) {
1917 creatingModuleDuringBuildSet.delete(module);
1918 }
1919 if (err) {
1920 if (!err.module) {
1921 err.module = module;
1922 }
1923 this.errors.push(err);
1924
1925 return callback(err);
1926 }
1927
1928 if (!recursive) {
1929 this.processModuleDependenciesNonRecursive(module);
1930 callback(null, module);
1931 return;
1932 }
1933
1934 // This avoids deadlocks for circular dependencies
1935 if (this.processDependenciesQueue.isProcessing(module)) {
1936 return callback();
1937 }
1938
1939 this.processModuleDependencies(module, err => {
1940 if (err) {
1941 return callback(err);
1942 }
1943 callback(null, module);
1944 });
1945 });
1946 }
1947
1948 /**
1949 * @param {FactorizeModuleOptions} options options object
1950 * @param {ModuleOrFactoryResultCallback} callback callback
1951 * @returns {void}
1952 */
1953 _factorizeModule(
1954 {
1955 currentProfile,
1956 factory,
1957 dependencies,
1958 originModule,
1959 factoryResult,
1960 contextInfo,
1961 context
1962 },
1963 callback
1964 ) {
1965 if (currentProfile !== undefined) {
1966 currentProfile.markFactoryStart();
1967 }
1968 factory.create(
1969 {
1970 contextInfo: {
1971 issuer: originModule ? originModule.nameForCondition() : "",
1972 issuerLayer: originModule ? originModule.layer : null,
1973 compiler: this.compiler.name,
1974 ...contextInfo
1975 },
1976 resolveOptions: originModule ? originModule.resolveOptions : undefined,
1977 context: context
1978 ? context
1979 : originModule
1980 ? originModule.context
1981 : this.compiler.context,
1982 dependencies: dependencies
1983 },
1984 (err, result) => {
1985 if (result) {
1986 // TODO webpack 6: remove
1987 // For backward-compat
1988 if (result.module === undefined && result instanceof Module) {
1989 result = {
1990 module: result
1991 };
1992 }
1993 if (!factoryResult) {
1994 const {
1995 fileDependencies,
1996 contextDependencies,
1997 missingDependencies
1998 } = result;
1999 if (fileDependencies) {
2000 this.fileDependencies.addAll(fileDependencies);
2001 }
2002 if (contextDependencies) {
2003 this.contextDependencies.addAll(contextDependencies);
2004 }
2005 if (missingDependencies) {
2006 this.missingDependencies.addAll(missingDependencies);
2007 }
2008 }
2009 }
2010 if (err) {
2011 const notFoundError = new ModuleNotFoundError(
2012 originModule,
2013 err,
2014 dependencies.map(d => d.loc).filter(Boolean)[0]
2015 );
2016 return callback(notFoundError, factoryResult ? result : undefined);
2017 }
2018 if (!result) {
2019 return callback();
2020 }
2021
2022 if (currentProfile !== undefined) {
2023 currentProfile.markFactoryEnd();
2024 }
2025
2026 callback(null, factoryResult ? result : result.module);
2027 }
2028 );
2029 }
2030
2031 /**
2032 * @param {string} context context string path
2033 * @param {Dependency} dependency dependency used to create Module chain
2034 * @param {ModuleCallback} callback callback for when module chain is complete
2035 * @returns {void} will throw if dependency instance is not a valid Dependency
2036 */
2037 addModuleChain(context, dependency, callback) {
2038 return this.addModuleTree({ context, dependency }, callback);
2039 }
2040
2041 /**
2042 * @param {Object} options options
2043 * @param {string} options.context context string path
2044 * @param {Dependency} options.dependency dependency used to create Module chain
2045 * @param {Partial<ModuleFactoryCreateDataContextInfo>=} options.contextInfo additional context info for the root module
2046 * @param {ModuleCallback} callback callback for when module chain is complete
2047 * @returns {void} will throw if dependency instance is not a valid Dependency
2048 */
2049 addModuleTree({ context, dependency, contextInfo }, callback) {
2050 if (
2051 typeof dependency !== "object" ||
2052 dependency === null ||
2053 !dependency.constructor
2054 ) {
2055 return callback(
2056 new WebpackError("Parameter 'dependency' must be a Dependency")
2057 );
2058 }
2059 const Dep = /** @type {DepConstructor} */ (dependency.constructor);
2060 const moduleFactory = this.dependencyFactories.get(Dep);
2061 if (!moduleFactory) {
2062 return callback(
2063 new WebpackError(
2064 `No dependency factory available for this dependency type: ${dependency.constructor.name}`
2065 )
2066 );
2067 }
2068
2069 this.handleModuleCreation(
2070 {
2071 factory: moduleFactory,
2072 dependencies: [dependency],
2073 originModule: null,
2074 contextInfo,
2075 context
2076 },
2077 (err, result) => {
2078 if (err && this.bail) {
2079 callback(err);
2080 this.buildQueue.stop();
2081 this.rebuildQueue.stop();
2082 this.processDependenciesQueue.stop();
2083 this.factorizeQueue.stop();
2084 } else if (!err && result) {
2085 callback(null, result);
2086 } else {
2087 callback();
2088 }
2089 }
2090 );
2091 }
2092
2093 /**
2094 * @param {string} context context path for entry
2095 * @param {Dependency} entry entry dependency that should be followed
2096 * @param {string | EntryOptions} optionsOrName options or deprecated name of entry
2097 * @param {ModuleCallback} callback callback function
2098 * @returns {void} returns
2099 */
2100 addEntry(context, entry, optionsOrName, callback) {
2101 // TODO webpack 6 remove
2102 const options =
2103 typeof optionsOrName === "object"
2104 ? optionsOrName
2105 : { name: optionsOrName };
2106
2107 this._addEntryItem(context, entry, "dependencies", options, callback);
2108 }
2109
2110 /**
2111 * @param {string} context context path for entry
2112 * @param {Dependency} dependency dependency that should be followed
2113 * @param {EntryOptions} options options
2114 * @param {ModuleCallback} callback callback function
2115 * @returns {void} returns
2116 */
2117 addInclude(context, dependency, options, callback) {
2118 this._addEntryItem(
2119 context,
2120 dependency,
2121 "includeDependencies",
2122 options,
2123 callback
2124 );
2125 }
2126
2127 /**
2128 * @param {string} context context path for entry
2129 * @param {Dependency} entry entry dependency that should be followed
2130 * @param {"dependencies" | "includeDependencies"} target type of entry
2131 * @param {EntryOptions} options options
2132 * @param {ModuleCallback} callback callback function
2133 * @returns {void} returns
2134 */
2135 _addEntryItem(context, entry, target, options, callback) {
2136 const { name } = options;
2137 let entryData =
2138 name !== undefined ? this.entries.get(name) : this.globalEntry;
2139 if (entryData === undefined) {
2140 entryData = {
2141 dependencies: [],
2142 includeDependencies: [],
2143 options: {
2144 name: undefined,
2145 ...options
2146 }
2147 };
2148 entryData[target].push(entry);
2149 this.entries.set(name, entryData);
2150 } else {
2151 entryData[target].push(entry);
2152 for (const key of Object.keys(options)) {
2153 if (options[key] === undefined) continue;
2154 if (entryData.options[key] === options[key]) continue;
2155 if (
2156 Array.isArray(entryData.options[key]) &&
2157 Array.isArray(options[key]) &&
2158 arrayEquals(entryData.options[key], options[key])
2159 ) {
2160 continue;
2161 }
2162 if (entryData.options[key] === undefined) {
2163 entryData.options[key] = options[key];
2164 } else {
2165 return callback(
2166 new WebpackError(
2167 `Conflicting entry option ${key} = ${entryData.options[key]} vs ${options[key]}`
2168 )
2169 );
2170 }
2171 }
2172 }
2173
2174 this.hooks.addEntry.call(entry, options);
2175
2176 this.addModuleTree(
2177 {
2178 context,
2179 dependency: entry,
2180 contextInfo: entryData.options.layer
2181 ? { issuerLayer: entryData.options.layer }
2182 : undefined
2183 },
2184 (err, module) => {
2185 if (err) {
2186 this.hooks.failedEntry.call(entry, options, err);
2187 return callback(err);
2188 }
2189 this.hooks.succeedEntry.call(entry, options, module);
2190 return callback(null, module);
2191 }
2192 );
2193 }
2194
2195 /**
2196 * @param {Module} module module to be rebuilt
2197 * @param {ModuleCallback} callback callback when module finishes rebuilding
2198 * @returns {void}
2199 */
2200 rebuildModule(module, callback) {
2201 this.rebuildQueue.add(module, callback);
2202 }
2203
2204 /**
2205 * @param {Module} module module to be rebuilt
2206 * @param {ModuleCallback} callback callback when module finishes rebuilding
2207 * @returns {void}
2208 */
2209 _rebuildModule(module, callback) {
2210 this.hooks.rebuildModule.call(module);
2211 const oldDependencies = module.dependencies.slice();
2212 const oldBlocks = module.blocks.slice();
2213 module.invalidateBuild();
2214 this.buildQueue.invalidate(module);
2215 this.buildModule(module, err => {
2216 if (err) {
2217 return this.hooks.finishRebuildingModule.callAsync(module, err2 => {
2218 if (err2) {
2219 callback(
2220 makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule")
2221 );
2222 return;
2223 }
2224 callback(err);
2225 });
2226 }
2227
2228 this.processDependenciesQueue.invalidate(module);
2229 this.moduleGraph.unfreeze();
2230 this.processModuleDependencies(module, err => {
2231 if (err) return callback(err);
2232 this.removeReasonsOfDependencyBlock(module, {
2233 dependencies: oldDependencies,
2234 blocks: oldBlocks
2235 });
2236 this.hooks.finishRebuildingModule.callAsync(module, err2 => {
2237 if (err2) {
2238 callback(
2239 makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule")
2240 );
2241 return;
2242 }
2243 callback(null, module);
2244 });
2245 });
2246 });
2247 }
2248
2249 _computeAffectedModules(modules) {
2250 const moduleMemCacheCache = this.compiler.moduleMemCaches;
2251 if (!moduleMemCacheCache) return;
2252 if (!this.moduleMemCaches) {
2253 this.moduleMemCaches = new Map();
2254 this.moduleGraph.setModuleMemCaches(this.moduleMemCaches);
2255 }
2256 const { moduleGraph, moduleMemCaches } = this;
2257 const affectedModules = new Set();
2258 const infectedModules = new Set();
2259 let statNew = 0;
2260 let statChanged = 0;
2261 let statUnchanged = 0;
2262 let statReferencesChanged = 0;
2263 let statWithoutBuild = 0;
2264
2265 const computeReferences = module => {
2266 /** @type {WeakMap<Dependency, Module>} */
2267 let references = undefined;
2268 for (const connection of moduleGraph.getOutgoingConnections(module)) {
2269 const d = connection.dependency;
2270 const m = connection.module;
2271 if (!d || !m || unsafeCacheDependencies.has(d)) continue;
2272 if (references === undefined) references = new WeakMap();
2273 references.set(d, m);
2274 }
2275 return references;
2276 };
2277
2278 /**
2279 * @param {Module} module the module
2280 * @param {WeakMap<Dependency, Module>} references references
2281 * @returns {boolean} true, when the references differ
2282 */
2283 const compareReferences = (module, references) => {
2284 if (references === undefined) return true;
2285 for (const connection of moduleGraph.getOutgoingConnections(module)) {
2286 const d = connection.dependency;
2287 if (!d) continue;
2288 const entry = references.get(d);
2289 if (entry === undefined) continue;
2290 if (entry !== connection.module) return false;
2291 }
2292 return true;
2293 };
2294
2295 const modulesWithoutCache = new Set(modules);
2296 for (const [module, cachedMemCache] of moduleMemCacheCache) {
2297 if (modulesWithoutCache.has(module)) {
2298 const buildInfo = module.buildInfo;
2299 if (buildInfo) {
2300 if (cachedMemCache.buildInfo !== buildInfo) {
2301 // use a new one
2302 const memCache = new WeakTupleMap();
2303 moduleMemCaches.set(module, memCache);
2304 affectedModules.add(module);
2305 cachedMemCache.buildInfo = buildInfo;
2306 cachedMemCache.references = computeReferences(module);
2307 cachedMemCache.memCache = memCache;
2308 statChanged++;
2309 } else if (!compareReferences(module, cachedMemCache.references)) {
2310 // use a new one
2311 const memCache = new WeakTupleMap();
2312 moduleMemCaches.set(module, memCache);
2313 affectedModules.add(module);
2314 cachedMemCache.references = computeReferences(module);
2315 cachedMemCache.memCache = memCache;
2316 statReferencesChanged++;
2317 } else {
2318 // keep the old mem cache
2319 moduleMemCaches.set(module, cachedMemCache.memCache);
2320 statUnchanged++;
2321 }
2322 } else {
2323 infectedModules.add(module);
2324 moduleMemCacheCache.delete(module);
2325 statWithoutBuild++;
2326 }
2327 modulesWithoutCache.delete(module);
2328 } else {
2329 moduleMemCacheCache.delete(module);
2330 }
2331 }
2332
2333 for (const module of modulesWithoutCache) {
2334 const buildInfo = module.buildInfo;
2335 if (buildInfo) {
2336 // create a new entry
2337 const memCache = new WeakTupleMap();
2338 moduleMemCacheCache.set(module, {
2339 buildInfo,
2340 references: computeReferences(module),
2341 memCache
2342 });
2343 moduleMemCaches.set(module, memCache);
2344 affectedModules.add(module);
2345 statNew++;
2346 } else {
2347 infectedModules.add(module);
2348 statWithoutBuild++;
2349 }
2350 }
2351
2352 const reduceAffectType = connections => {
2353 let affected = false;
2354 for (const { dependency } of connections) {
2355 if (!dependency) continue;
2356 const type = dependency.couldAffectReferencingModule();
2357 if (type === Dependency.TRANSITIVE) return Dependency.TRANSITIVE;
2358 if (type === false) continue;
2359 affected = true;
2360 }
2361 return affected;
2362 };
2363 const directOnlyInfectedModules = new Set();
2364 for (const module of infectedModules) {
2365 for (const [
2366 referencingModule,
2367 connections
2368 ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2369 if (!referencingModule) continue;
2370 if (infectedModules.has(referencingModule)) continue;
2371 const type = reduceAffectType(connections);
2372 if (!type) continue;
2373 if (type === true) {
2374 directOnlyInfectedModules.add(referencingModule);
2375 } else {
2376 infectedModules.add(referencingModule);
2377 }
2378 }
2379 }
2380 for (const module of directOnlyInfectedModules) infectedModules.add(module);
2381 const directOnlyAffectModules = new Set();
2382 for (const module of affectedModules) {
2383 for (const [
2384 referencingModule,
2385 connections
2386 ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
2387 if (!referencingModule) continue;
2388 if (infectedModules.has(referencingModule)) continue;
2389 if (affectedModules.has(referencingModule)) continue;
2390 const type = reduceAffectType(connections);
2391 if (!type) continue;
2392 if (type === true) {
2393 directOnlyAffectModules.add(referencingModule);
2394 } else {
2395 affectedModules.add(referencingModule);
2396 }
2397 const memCache = new WeakTupleMap();
2398 const cache = moduleMemCacheCache.get(referencingModule);
2399 cache.memCache = memCache;
2400 moduleMemCaches.set(referencingModule, memCache);
2401 }
2402 }
2403 for (const module of directOnlyAffectModules) affectedModules.add(module);
2404 this.logger.log(
2405 `${Math.round(
2406 (100 * (affectedModules.size + infectedModules.size)) /
2407 this.modules.size
2408 )}% (${affectedModules.size} affected + ${
2409 infectedModules.size
2410 } infected of ${
2411 this.modules.size
2412 }) modules flagged as affected (${statNew} new modules, ${statChanged} changed, ${statReferencesChanged} references changed, ${statUnchanged} unchanged, ${statWithoutBuild} were not built)`
2413 );
2414 }
2415
2416 _computeAffectedModulesWithChunkGraph() {
2417 const { moduleMemCaches } = this;
2418 if (!moduleMemCaches) return;
2419 const moduleMemCaches2 = (this.moduleMemCaches2 = new Map());
2420 const { moduleGraph, chunkGraph } = this;
2421 const key = "memCache2";
2422 let statUnchanged = 0;
2423 let statChanged = 0;
2424 let statNew = 0;
2425 /**
2426 * @param {Module} module module
2427 * @returns {{ modules?: Map<Module, string | number | undefined>, blocks?: (string | number)[] }} references
2428 */
2429 const computeReferences = module => {
2430 /** @type {Map<Module, string | number | undefined>} */
2431 let modules = undefined;
2432 /** @type {(string | number)[] | undefined} */
2433 let blocks = undefined;
2434 const outgoing = moduleGraph.getOutgoingConnectionsByModule(module);
2435 if (outgoing !== undefined) {
2436 for (const m of outgoing.keys()) {
2437 if (!m) continue;
2438 if (modules === undefined) modules = new Map();
2439 modules.set(m, chunkGraph.getModuleId(m));
2440 }
2441 }
2442 if (module.blocks.length > 0) {
2443 blocks = [];
2444 const queue = Array.from(module.blocks);
2445 for (const block of queue) {
2446 const chunkGroup = chunkGraph.getBlockChunkGroup(block);
2447 if (chunkGroup) {
2448 for (const chunk of chunkGroup.chunks) {
2449 blocks.push(chunk.id);
2450 }
2451 } else {
2452 blocks.push(null);
2453 }
2454 queue.push.apply(queue, block.blocks);
2455 }
2456 }
2457 return { modules, blocks };
2458 };
2459 /**
2460 * @param {Module} module module
2461 * @param {Object} references references
2462 * @param {Map<Module, string | number>=} references.modules modules
2463 * @param {(string | number)[]=} references.blocks blocks
2464 * @returns {boolean} ok?
2465 */
2466 const compareReferences = (module, { modules, blocks }) => {
2467 if (modules !== undefined) {
2468 for (const [module, id] of modules) {
2469 if (chunkGraph.getModuleId(module) !== id) return false;
2470 }
2471 }
2472 if (blocks !== undefined) {
2473 const queue = Array.from(module.blocks);
2474 let i = 0;
2475 for (const block of queue) {
2476 const chunkGroup = chunkGraph.getBlockChunkGroup(block);
2477 if (chunkGroup) {
2478 for (const chunk of chunkGroup.chunks) {
2479 if (i >= blocks.length || blocks[i++] !== chunk.id) return false;
2480 }
2481 } else {
2482 if (i >= blocks.length || blocks[i++] !== null) return false;
2483 }
2484 queue.push.apply(queue, block.blocks);
2485 }
2486 if (i !== blocks.length) return false;
2487 }
2488 return true;
2489 };
2490
2491 for (const [module, memCache] of moduleMemCaches) {
2492 /** @type {{ references: { modules?: Map<Module, string | number | undefined>, blocks?: (string | number)[]}, memCache: WeakTupleMap<any[], any> }} */
2493 const cache = memCache.get(key);
2494 if (cache === undefined) {
2495 const memCache2 = new WeakTupleMap();
2496 memCache.set(key, {
2497 references: computeReferences(module),
2498 memCache: memCache2
2499 });
2500 moduleMemCaches2.set(module, memCache2);
2501 statNew++;
2502 } else if (!compareReferences(module, cache.references)) {
2503 const memCache = new WeakTupleMap();
2504 cache.references = computeReferences(module);
2505 cache.memCache = memCache;
2506 moduleMemCaches2.set(module, memCache);
2507 statChanged++;
2508 } else {
2509 moduleMemCaches2.set(module, cache.memCache);
2510 statUnchanged++;
2511 }
2512 }
2513
2514 this.logger.log(
2515 `${Math.round(
2516 (100 * statChanged) / (statNew + statChanged + statUnchanged)
2517 )}% modules flagged as affected by chunk graph (${statNew} new modules, ${statChanged} changed, ${statUnchanged} unchanged)`
2518 );
2519 }
2520
2521 finish(callback) {
2522 this.factorizeQueue.clear();
2523 if (this.profile) {
2524 this.logger.time("finish module profiles");
2525 const ParallelismFactorCalculator = require("./util/ParallelismFactorCalculator");
2526 const p = new ParallelismFactorCalculator();
2527 const moduleGraph = this.moduleGraph;
2528 const modulesWithProfiles = new Map();
2529 for (const module of this.modules) {
2530 const profile = moduleGraph.getProfile(module);
2531 if (!profile) continue;
2532 modulesWithProfiles.set(module, profile);
2533 p.range(
2534 profile.buildingStartTime,
2535 profile.buildingEndTime,
2536 f => (profile.buildingParallelismFactor = f)
2537 );
2538 p.range(
2539 profile.factoryStartTime,
2540 profile.factoryEndTime,
2541 f => (profile.factoryParallelismFactor = f)
2542 );
2543 p.range(
2544 profile.integrationStartTime,
2545 profile.integrationEndTime,
2546 f => (profile.integrationParallelismFactor = f)
2547 );
2548 p.range(
2549 profile.storingStartTime,
2550 profile.storingEndTime,
2551 f => (profile.storingParallelismFactor = f)
2552 );
2553 p.range(
2554 profile.restoringStartTime,
2555 profile.restoringEndTime,
2556 f => (profile.restoringParallelismFactor = f)
2557 );
2558 if (profile.additionalFactoryTimes) {
2559 for (const { start, end } of profile.additionalFactoryTimes) {
2560 const influence = (end - start) / profile.additionalFactories;
2561 p.range(
2562 start,
2563 end,
2564 f =>
2565 (profile.additionalFactoriesParallelismFactor += f * influence)
2566 );
2567 }
2568 }
2569 }
2570 p.calculate();
2571
2572 const logger = this.getLogger("webpack.Compilation.ModuleProfile");
2573 const logByValue = (value, msg) => {
2574 if (value > 1000) {
2575 logger.error(msg);
2576 } else if (value > 500) {
2577 logger.warn(msg);
2578 } else if (value > 200) {
2579 logger.info(msg);
2580 } else if (value > 30) {
2581 logger.log(msg);
2582 } else {
2583 logger.debug(msg);
2584 }
2585 };
2586 const logNormalSummary = (category, getDuration, getParallelism) => {
2587 let sum = 0;
2588 let max = 0;
2589 for (const [module, profile] of modulesWithProfiles) {
2590 const p = getParallelism(profile);
2591 const d = getDuration(profile);
2592 if (d === 0 || p === 0) continue;
2593 const t = d / p;
2594 sum += t;
2595 if (t <= 10) continue;
2596 logByValue(
2597 t,
2598 ` | ${Math.round(t)} ms${
2599 p >= 1.1 ? ` (parallelism ${Math.round(p * 10) / 10})` : ""
2600 } ${category} > ${module.readableIdentifier(this.requestShortener)}`
2601 );
2602 max = Math.max(max, t);
2603 }
2604 if (sum <= 10) return;
2605 logByValue(
2606 Math.max(sum / 10, max),
2607 `${Math.round(sum)} ms ${category}`
2608 );
2609 };
2610 const logByLoadersSummary = (category, getDuration, getParallelism) => {
2611 const map = new Map();
2612 for (const [module, profile] of modulesWithProfiles) {
2613 const list = provide(
2614 map,
2615 module.type + "!" + module.identifier().replace(/(!|^)[^!]*$/, ""),
2616 () => []
2617 );
2618 list.push({ module, profile });
2619 }
2620
2621 let sum = 0;
2622 let max = 0;
2623 for (const [key, modules] of map) {
2624 let innerSum = 0;
2625 let innerMax = 0;
2626 for (const { module, profile } of modules) {
2627 const p = getParallelism(profile);
2628 const d = getDuration(profile);
2629 if (d === 0 || p === 0) continue;
2630 const t = d / p;
2631 innerSum += t;
2632 if (t <= 10) continue;
2633 logByValue(
2634 t,
2635 ` | | ${Math.round(t)} ms${
2636 p >= 1.1 ? ` (parallelism ${Math.round(p * 10) / 10})` : ""
2637 } ${category} > ${module.readableIdentifier(
2638 this.requestShortener
2639 )}`
2640 );
2641 innerMax = Math.max(innerMax, t);
2642 }
2643 sum += innerSum;
2644 if (innerSum <= 10) continue;
2645 const idx = key.indexOf("!");
2646 const loaders = key.slice(idx + 1);
2647 const moduleType = key.slice(0, idx);
2648 const t = Math.max(innerSum / 10, innerMax);
2649 logByValue(
2650 t,
2651 ` | ${Math.round(innerSum)} ms ${category} > ${
2652 loaders
2653 ? `${
2654 modules.length
2655 } x ${moduleType} with ${this.requestShortener.shorten(
2656 loaders
2657 )}`
2658 : `${modules.length} x ${moduleType}`
2659 }`
2660 );
2661 max = Math.max(max, t);
2662 }
2663 if (sum <= 10) return;
2664 logByValue(
2665 Math.max(sum / 10, max),
2666 `${Math.round(sum)} ms ${category}`
2667 );
2668 };
2669 logNormalSummary(
2670 "resolve to new modules",
2671 p => p.factory,
2672 p => p.factoryParallelismFactor
2673 );
2674 logNormalSummary(
2675 "resolve to existing modules",
2676 p => p.additionalFactories,
2677 p => p.additionalFactoriesParallelismFactor
2678 );
2679 logNormalSummary(
2680 "integrate modules",
2681 p => p.restoring,
2682 p => p.restoringParallelismFactor
2683 );
2684 logByLoadersSummary(
2685 "build modules",
2686 p => p.building,
2687 p => p.buildingParallelismFactor
2688 );
2689 logNormalSummary(
2690 "store modules",
2691 p => p.storing,
2692 p => p.storingParallelismFactor
2693 );
2694 logNormalSummary(
2695 "restore modules",
2696 p => p.restoring,
2697 p => p.restoringParallelismFactor
2698 );
2699 this.logger.timeEnd("finish module profiles");
2700 }
2701 this.logger.time("compute affected modules");
2702 this._computeAffectedModules(this.modules);
2703 this.logger.timeEnd("compute affected modules");
2704 this.logger.time("finish modules");
2705 const { modules, moduleMemCaches } = this;
2706 this.hooks.finishModules.callAsync(modules, err => {
2707 this.logger.timeEnd("finish modules");
2708 if (err) return callback(err);
2709
2710 // extract warnings and errors from modules
2711 this.moduleGraph.freeze("dependency errors");
2712 // TODO keep a cacheToken (= {}) for each module in the graph
2713 // create a new one per compilation and flag all updated files
2714 // and parents with it
2715 this.logger.time("report dependency errors and warnings");
2716 for (const module of modules) {
2717 // TODO only run for modules with changed cacheToken
2718 // global WeakMap<CacheToken, WeakSet<Module>> to keep modules without errors/warnings
2719 const memCache = moduleMemCaches && moduleMemCaches.get(module);
2720 if (memCache && memCache.get("noWarningsOrErrors")) continue;
2721 let hasProblems = this.reportDependencyErrorsAndWarnings(module, [
2722 module
2723 ]);
2724 const errors = module.getErrors();
2725 if (errors !== undefined) {
2726 for (const error of errors) {
2727 if (!error.module) {
2728 error.module = module;
2729 }
2730 this.errors.push(error);
2731 hasProblems = true;
2732 }
2733 }
2734 const warnings = module.getWarnings();
2735 if (warnings !== undefined) {
2736 for (const warning of warnings) {
2737 if (!warning.module) {
2738 warning.module = module;
2739 }
2740 this.warnings.push(warning);
2741 hasProblems = true;
2742 }
2743 }
2744 if (!hasProblems && memCache) memCache.set("noWarningsOrErrors", true);
2745 }
2746 this.moduleGraph.unfreeze();
2747 this.logger.timeEnd("report dependency errors and warnings");
2748
2749 callback();
2750 });
2751 }
2752
2753 unseal() {
2754 this.hooks.unseal.call();
2755 this.chunks.clear();
2756 this.chunkGroups.length = 0;
2757 this.namedChunks.clear();
2758 this.namedChunkGroups.clear();
2759 this.entrypoints.clear();
2760 this.additionalChunkAssets.length = 0;
2761 this.assets = {};
2762 this.assetsInfo.clear();
2763 this.moduleGraph.removeAllModuleAttributes();
2764 this.moduleGraph.unfreeze();
2765 this.moduleMemCaches2 = undefined;
2766 }
2767
2768 /**
2769 * @param {Callback} callback signals when the call finishes
2770 * @returns {void}
2771 */
2772 seal(callback) {
2773 const finalCallback = err => {
2774 this.factorizeQueue.clear();
2775 this.buildQueue.clear();
2776 this.rebuildQueue.clear();
2777 this.processDependenciesQueue.clear();
2778 this.addModuleQueue.clear();
2779 return callback(err);
2780 };
2781 const chunkGraph = new ChunkGraph(
2782 this.moduleGraph,
2783 this.outputOptions.hashFunction
2784 );
2785 this.chunkGraph = chunkGraph;
2786
2787 if (this._backCompat) {
2788 for (const module of this.modules) {
2789 ChunkGraph.setChunkGraphForModule(module, chunkGraph);
2790 }
2791 }
2792
2793 this.hooks.seal.call();
2794
2795 this.logger.time("optimize dependencies");
2796 while (this.hooks.optimizeDependencies.call(this.modules)) {
2797 /* empty */
2798 }
2799 this.hooks.afterOptimizeDependencies.call(this.modules);
2800 this.logger.timeEnd("optimize dependencies");
2801
2802 this.logger.time("create chunks");
2803 this.hooks.beforeChunks.call();
2804 this.moduleGraph.freeze("seal");
2805 /** @type {Map<Entrypoint, Module[]>} */
2806 const chunkGraphInit = new Map();
2807 for (const [name, { dependencies, includeDependencies, options }] of this
2808 .entries) {
2809 const chunk = this.addChunk(name);
2810 if (options.filename) {
2811 chunk.filenameTemplate = options.filename;
2812 }
2813 const entrypoint = new Entrypoint(options);
2814 if (!options.dependOn && !options.runtime) {
2815 entrypoint.setRuntimeChunk(chunk);
2816 }
2817 entrypoint.setEntrypointChunk(chunk);
2818 this.namedChunkGroups.set(name, entrypoint);
2819 this.entrypoints.set(name, entrypoint);
2820 this.chunkGroups.push(entrypoint);
2821 connectChunkGroupAndChunk(entrypoint, chunk);
2822
2823 const entryModules = new Set();
2824 for (const dep of [...this.globalEntry.dependencies, ...dependencies]) {
2825 entrypoint.addOrigin(null, { name }, /** @type {any} */ (dep).request);
2826
2827 const module = this.moduleGraph.getModule(dep);
2828 if (module) {
2829 chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
2830 entryModules.add(module);
2831 const modulesList = chunkGraphInit.get(entrypoint);
2832 if (modulesList === undefined) {
2833 chunkGraphInit.set(entrypoint, [module]);
2834 } else {
2835 modulesList.push(module);
2836 }
2837 }
2838 }
2839
2840 this.assignDepths(entryModules);
2841
2842 const mapAndSort = deps =>
2843 deps
2844 .map(dep => this.moduleGraph.getModule(dep))
2845 .filter(Boolean)
2846 .sort(compareModulesByIdentifier);
2847 const includedModules = [
2848 ...mapAndSort(this.globalEntry.includeDependencies),
2849 ...mapAndSort(includeDependencies)
2850 ];
2851
2852 let modulesList = chunkGraphInit.get(entrypoint);
2853 if (modulesList === undefined) {
2854 chunkGraphInit.set(entrypoint, (modulesList = []));
2855 }
2856 for (const module of includedModules) {
2857 this.assignDepth(module);
2858 modulesList.push(module);
2859 }
2860 }
2861 const runtimeChunks = new Set();
2862 outer: for (const [
2863 name,
2864 {
2865 options: { dependOn, runtime }
2866 }
2867 ] of this.entries) {
2868 if (dependOn && runtime) {
2869 const err =
2870 new WebpackError(`Entrypoint '${name}' has 'dependOn' and 'runtime' specified. This is not valid.
2871Entrypoints that depend on other entrypoints do not have their own runtime.
2872They will use the runtime(s) from referenced entrypoints instead.
2873Remove the 'runtime' option from the entrypoint.`);
2874 const entry = this.entrypoints.get(name);
2875 err.chunk = entry.getEntrypointChunk();
2876 this.errors.push(err);
2877 }
2878 if (dependOn) {
2879 const entry = this.entrypoints.get(name);
2880 const referencedChunks = entry
2881 .getEntrypointChunk()
2882 .getAllReferencedChunks();
2883 const dependOnEntries = [];
2884 for (const dep of dependOn) {
2885 const dependency = this.entrypoints.get(dep);
2886 if (!dependency) {
2887 throw new Error(
2888 `Entry ${name} depends on ${dep}, but this entry was not found`
2889 );
2890 }
2891 if (referencedChunks.has(dependency.getEntrypointChunk())) {
2892 const err = new WebpackError(
2893 `Entrypoints '${name}' and '${dep}' use 'dependOn' to depend on each other in a circular way.`
2894 );
2895 const entryChunk = entry.getEntrypointChunk();
2896 err.chunk = entryChunk;
2897 this.errors.push(err);
2898 entry.setRuntimeChunk(entryChunk);
2899 continue outer;
2900 }
2901 dependOnEntries.push(dependency);
2902 }
2903 for (const dependency of dependOnEntries) {
2904 connectChunkGroupParentAndChild(dependency, entry);
2905 }
2906 } else if (runtime) {
2907 const entry = this.entrypoints.get(name);
2908 let chunk = this.namedChunks.get(runtime);
2909 if (chunk) {
2910 if (!runtimeChunks.has(chunk)) {
2911 const err =
2912 new WebpackError(`Entrypoint '${name}' has a 'runtime' option which points to another entrypoint named '${runtime}'.
2913It's not valid to use other entrypoints as runtime chunk.
2914Did you mean to use 'dependOn: ${JSON.stringify(
2915 runtime
2916 )}' instead to allow using entrypoint '${name}' within the runtime of entrypoint '${runtime}'? For this '${runtime}' must always be loaded when '${name}' is used.
2917Or do you want to use the entrypoints '${name}' and '${runtime}' independently on the same page with a shared runtime? In this case give them both the same value for the 'runtime' option. It must be a name not already used by an entrypoint.`);
2918 const entryChunk = entry.getEntrypointChunk();
2919 err.chunk = entryChunk;
2920 this.errors.push(err);
2921 entry.setRuntimeChunk(entryChunk);
2922 continue;
2923 }
2924 } else {
2925 chunk = this.addChunk(runtime);
2926 chunk.preventIntegration = true;
2927 runtimeChunks.add(chunk);
2928 }
2929 entry.unshiftChunk(chunk);
2930 chunk.addGroup(entry);
2931 entry.setRuntimeChunk(chunk);
2932 }
2933 }
2934 buildChunkGraph(this, chunkGraphInit);
2935 this.hooks.afterChunks.call(this.chunks);
2936 this.logger.timeEnd("create chunks");
2937
2938 this.logger.time("optimize");
2939 this.hooks.optimize.call();
2940
2941 while (this.hooks.optimizeModules.call(this.modules)) {
2942 /* empty */
2943 }
2944 this.hooks.afterOptimizeModules.call(this.modules);
2945
2946 while (this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups)) {
2947 /* empty */
2948 }
2949 this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
2950
2951 this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
2952 if (err) {
2953 return finalCallback(
2954 makeWebpackError(err, "Compilation.hooks.optimizeTree")
2955 );
2956 }
2957
2958 this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
2959
2960 this.hooks.optimizeChunkModules.callAsync(
2961 this.chunks,
2962 this.modules,
2963 err => {
2964 if (err) {
2965 return finalCallback(
2966 makeWebpackError(err, "Compilation.hooks.optimizeChunkModules")
2967 );
2968 }
2969
2970 this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
2971
2972 const shouldRecord = this.hooks.shouldRecord.call() !== false;
2973
2974 this.hooks.reviveModules.call(this.modules, this.records);
2975 this.hooks.beforeModuleIds.call(this.modules);
2976 this.hooks.moduleIds.call(this.modules);
2977 this.hooks.optimizeModuleIds.call(this.modules);
2978 this.hooks.afterOptimizeModuleIds.call(this.modules);
2979
2980 this.hooks.reviveChunks.call(this.chunks, this.records);
2981 this.hooks.beforeChunkIds.call(this.chunks);
2982 this.hooks.chunkIds.call(this.chunks);
2983 this.hooks.optimizeChunkIds.call(this.chunks);
2984 this.hooks.afterOptimizeChunkIds.call(this.chunks);
2985
2986 this.assignRuntimeIds();
2987
2988 this.logger.time("compute affected modules with chunk graph");
2989 this._computeAffectedModulesWithChunkGraph();
2990 this.logger.timeEnd("compute affected modules with chunk graph");
2991
2992 this.sortItemsWithChunkIds();
2993
2994 if (shouldRecord) {
2995 this.hooks.recordModules.call(this.modules, this.records);
2996 this.hooks.recordChunks.call(this.chunks, this.records);
2997 }
2998
2999 this.hooks.optimizeCodeGeneration.call(this.modules);
3000 this.logger.timeEnd("optimize");
3001
3002 this.logger.time("module hashing");
3003 this.hooks.beforeModuleHash.call();
3004 this.createModuleHashes();
3005 this.hooks.afterModuleHash.call();
3006 this.logger.timeEnd("module hashing");
3007
3008 this.logger.time("code generation");
3009 this.hooks.beforeCodeGeneration.call();
3010 this.codeGeneration(err => {
3011 if (err) {
3012 return finalCallback(err);
3013 }
3014 this.hooks.afterCodeGeneration.call();
3015 this.logger.timeEnd("code generation");
3016
3017 this.logger.time("runtime requirements");
3018 this.hooks.beforeRuntimeRequirements.call();
3019 this.processRuntimeRequirements();
3020 this.hooks.afterRuntimeRequirements.call();
3021 this.logger.timeEnd("runtime requirements");
3022
3023 this.logger.time("hashing");
3024 this.hooks.beforeHash.call();
3025 const codeGenerationJobs = this.createHash();
3026 this.hooks.afterHash.call();
3027 this.logger.timeEnd("hashing");
3028
3029 this._runCodeGenerationJobs(codeGenerationJobs, err => {
3030 if (err) {
3031 return finalCallback(err);
3032 }
3033
3034 if (shouldRecord) {
3035 this.logger.time("record hash");
3036 this.hooks.recordHash.call(this.records);
3037 this.logger.timeEnd("record hash");
3038 }
3039
3040 this.logger.time("module assets");
3041 this.clearAssets();
3042
3043 this.hooks.beforeModuleAssets.call();
3044 this.createModuleAssets();
3045 this.logger.timeEnd("module assets");
3046
3047 const cont = () => {
3048 this.logger.time("process assets");
3049 this.hooks.processAssets.callAsync(this.assets, err => {
3050 if (err) {
3051 return finalCallback(
3052 makeWebpackError(err, "Compilation.hooks.processAssets")
3053 );
3054 }
3055 this.hooks.afterProcessAssets.call(this.assets);
3056 this.logger.timeEnd("process assets");
3057 this.assets = this._backCompat
3058 ? soonFrozenObjectDeprecation(
3059 this.assets,
3060 "Compilation.assets",
3061 "DEP_WEBPACK_COMPILATION_ASSETS",
3062 `BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation.
3063 Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
3064 Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.`
3065 )
3066 : Object.freeze(this.assets);
3067
3068 this.summarizeDependencies();
3069 if (shouldRecord) {
3070 this.hooks.record.call(this, this.records);
3071 }
3072
3073 if (this.hooks.needAdditionalSeal.call()) {
3074 this.unseal();
3075 return this.seal(callback);
3076 }
3077 return this.hooks.afterSeal.callAsync(err => {
3078 if (err) {
3079 return finalCallback(
3080 makeWebpackError(err, "Compilation.hooks.afterSeal")
3081 );
3082 }
3083 this.fileSystemInfo.logStatistics();
3084 finalCallback();
3085 });
3086 });
3087 };
3088
3089 this.logger.time("create chunk assets");
3090 if (this.hooks.shouldGenerateChunkAssets.call() !== false) {
3091 this.hooks.beforeChunkAssets.call();
3092 this.createChunkAssets(err => {
3093 this.logger.timeEnd("create chunk assets");
3094 if (err) {
3095 return finalCallback(err);
3096 }
3097 cont();
3098 });
3099 } else {
3100 this.logger.timeEnd("create chunk assets");
3101 cont();
3102 }
3103 });
3104 });
3105 }
3106 );
3107 });
3108 }
3109
3110 /**
3111 * @param {Module} module module to report from
3112 * @param {DependenciesBlock[]} blocks blocks to report from
3113 * @returns {boolean} true, when it has warnings or errors
3114 */
3115 reportDependencyErrorsAndWarnings(module, blocks) {
3116 let hasProblems = false;
3117 for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
3118 const block = blocks[indexBlock];
3119 const dependencies = block.dependencies;
3120
3121 for (let indexDep = 0; indexDep < dependencies.length; indexDep++) {
3122 const d = dependencies[indexDep];
3123
3124 const warnings = d.getWarnings(this.moduleGraph);
3125 if (warnings) {
3126 for (let indexWar = 0; indexWar < warnings.length; indexWar++) {
3127 const w = warnings[indexWar];
3128
3129 const warning = new ModuleDependencyWarning(module, w, d.loc);
3130 this.warnings.push(warning);
3131 hasProblems = true;
3132 }
3133 }
3134 const errors = d.getErrors(this.moduleGraph);
3135 if (errors) {
3136 for (let indexErr = 0; indexErr < errors.length; indexErr++) {
3137 const e = errors[indexErr];
3138
3139 const error = new ModuleDependencyError(module, e, d.loc);
3140 this.errors.push(error);
3141 hasProblems = true;
3142 }
3143 }
3144 }
3145
3146 if (this.reportDependencyErrorsAndWarnings(module, block.blocks))
3147 hasProblems = true;
3148 }
3149 return hasProblems;
3150 }
3151
3152 codeGeneration(callback) {
3153 const { chunkGraph } = this;
3154 this.codeGenerationResults = new CodeGenerationResults(
3155 this.outputOptions.hashFunction
3156 );
3157 /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */
3158 const jobs = [];
3159 for (const module of this.modules) {
3160 const runtimes = chunkGraph.getModuleRuntimes(module);
3161 if (runtimes.size === 1) {
3162 for (const runtime of runtimes) {
3163 const hash = chunkGraph.getModuleHash(module, runtime);
3164 jobs.push({ module, hash, runtime, runtimes: [runtime] });
3165 }
3166 } else if (runtimes.size > 1) {
3167 /** @type {Map<string, { runtimes: RuntimeSpec[] }>} */
3168 const map = new Map();
3169 for (const runtime of runtimes) {
3170 const hash = chunkGraph.getModuleHash(module, runtime);
3171 const job = map.get(hash);
3172 if (job === undefined) {
3173 const newJob = { module, hash, runtime, runtimes: [runtime] };
3174 jobs.push(newJob);
3175 map.set(hash, newJob);
3176 } else {
3177 job.runtimes.push(runtime);
3178 }
3179 }
3180 }
3181 }
3182
3183 this._runCodeGenerationJobs(jobs, callback);
3184 }
3185
3186 _runCodeGenerationJobs(jobs, callback) {
3187 let statModulesFromCache = 0;
3188 let statModulesGenerated = 0;
3189 const { chunkGraph, moduleGraph, dependencyTemplates, runtimeTemplate } =
3190 this;
3191 const results = this.codeGenerationResults;
3192 const errors = [];
3193 asyncLib.eachLimit(
3194 jobs,
3195 this.options.parallelism,
3196 ({ module, hash, runtime, runtimes }, callback) => {
3197 this._codeGenerationModule(
3198 module,
3199 runtime,
3200 runtimes,
3201 hash,
3202 dependencyTemplates,
3203 chunkGraph,
3204 moduleGraph,
3205 runtimeTemplate,
3206 errors,
3207 results,
3208 (err, codeGenerated) => {
3209 if (codeGenerated) statModulesGenerated++;
3210 else statModulesFromCache++;
3211 callback(err);
3212 }
3213 );
3214 },
3215 err => {
3216 if (err) return callback(err);
3217 if (errors.length > 0) {
3218 errors.sort(
3219 compareSelect(err => err.module, compareModulesByIdentifier)
3220 );
3221 for (const error of errors) {
3222 this.errors.push(error);
3223 }
3224 }
3225 this.logger.log(
3226 `${Math.round(
3227 (100 * statModulesGenerated) /
3228 (statModulesGenerated + statModulesFromCache)
3229 )}% code generated (${statModulesGenerated} generated, ${statModulesFromCache} from cache)`
3230 );
3231 callback();
3232 }
3233 );
3234 }
3235
3236 /**
3237 * @param {Module} module module
3238 * @param {RuntimeSpec} runtime runtime
3239 * @param {RuntimeSpec[]} runtimes runtimes
3240 * @param {string} hash hash
3241 * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
3242 * @param {ChunkGraph} chunkGraph chunkGraph
3243 * @param {ModuleGraph} moduleGraph moduleGraph
3244 * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
3245 * @param {WebpackError[]} errors errors
3246 * @param {CodeGenerationResults} results results
3247 * @param {function(WebpackError=, boolean=): void} callback callback
3248 */
3249 _codeGenerationModule(
3250 module,
3251 runtime,
3252 runtimes,
3253 hash,
3254 dependencyTemplates,
3255 chunkGraph,
3256 moduleGraph,
3257 runtimeTemplate,
3258 errors,
3259 results,
3260 callback
3261 ) {
3262 let codeGenerated = false;
3263 const cache = new MultiItemCache(
3264 runtimes.map(runtime =>
3265 this._codeGenerationCache.getItemCache(
3266 `${module.identifier()}|${getRuntimeKey(runtime)}`,
3267 `${hash}|${dependencyTemplates.getHash()}`
3268 )
3269 )
3270 );
3271 cache.get((err, cachedResult) => {
3272 if (err) return callback(err);
3273 let result;
3274 if (!cachedResult) {
3275 try {
3276 codeGenerated = true;
3277 this.codeGeneratedModules.add(module);
3278 result = module.codeGeneration({
3279 chunkGraph,
3280 moduleGraph,
3281 dependencyTemplates,
3282 runtimeTemplate,
3283 runtime
3284 });
3285 } catch (err) {
3286 errors.push(new CodeGenerationError(module, err));
3287 result = cachedResult = {
3288 sources: new Map(),
3289 runtimeRequirements: null
3290 };
3291 }
3292 } else {
3293 result = cachedResult;
3294 }
3295 for (const runtime of runtimes) {
3296 results.add(module, runtime, result);
3297 }
3298 if (!cachedResult) {
3299 cache.store(result, err => callback(err, codeGenerated));
3300 } else {
3301 callback(null, codeGenerated);
3302 }
3303 });
3304 }
3305
3306 _getChunkGraphEntries() {
3307 /** @type {Set<Chunk>} */
3308 const treeEntries = new Set();
3309 for (const ep of this.entrypoints.values()) {
3310 const chunk = ep.getRuntimeChunk();
3311 if (chunk) treeEntries.add(chunk);
3312 }
3313 for (const ep of this.asyncEntrypoints) {
3314 const chunk = ep.getRuntimeChunk();
3315 if (chunk) treeEntries.add(chunk);
3316 }
3317 return treeEntries;
3318 }
3319
3320 /**
3321 * @param {Object} options options
3322 * @param {ChunkGraph=} options.chunkGraph the chunk graph
3323 * @param {Iterable<Module>=} options.modules modules
3324 * @param {Iterable<Chunk>=} options.chunks chunks
3325 * @param {CodeGenerationResults=} options.codeGenerationResults codeGenerationResults
3326 * @param {Iterable<Chunk>=} options.chunkGraphEntries chunkGraphEntries
3327 * @returns {void}
3328 */
3329 processRuntimeRequirements({
3330 chunkGraph = this.chunkGraph,
3331 modules = this.modules,
3332 chunks = this.chunks,
3333 codeGenerationResults = this.codeGenerationResults,
3334 chunkGraphEntries = this._getChunkGraphEntries()
3335 } = {}) {
3336 const context = { chunkGraph, codeGenerationResults };
3337 const { moduleMemCaches2 } = this;
3338 this.logger.time("runtime requirements.modules");
3339 const additionalModuleRuntimeRequirements =
3340 this.hooks.additionalModuleRuntimeRequirements;
3341 const runtimeRequirementInModule = this.hooks.runtimeRequirementInModule;
3342 for (const module of modules) {
3343 if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
3344 const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
3345 for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3346 if (memCache) {
3347 const cached = memCache.get(
3348 `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`
3349 );
3350 if (cached !== undefined) {
3351 if (cached !== null) {
3352 chunkGraph.addModuleRuntimeRequirements(
3353 module,
3354 runtime,
3355 cached,
3356 false
3357 );
3358 }
3359 continue;
3360 }
3361 }
3362 let set;
3363 const runtimeRequirements =
3364 codeGenerationResults.getRuntimeRequirements(module, runtime);
3365 if (runtimeRequirements && runtimeRequirements.size > 0) {
3366 set = new Set(runtimeRequirements);
3367 } else if (additionalModuleRuntimeRequirements.isUsed()) {
3368 set = new Set();
3369 } else {
3370 if (memCache) {
3371 memCache.set(
3372 `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
3373 null
3374 );
3375 }
3376 continue;
3377 }
3378 additionalModuleRuntimeRequirements.call(module, set, context);
3379
3380 for (const r of set) {
3381 const hook = runtimeRequirementInModule.get(r);
3382 if (hook !== undefined) hook.call(module, set, context);
3383 }
3384 if (set.size === 0) {
3385 if (memCache) {
3386 memCache.set(
3387 `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
3388 null
3389 );
3390 }
3391 } else {
3392 if (memCache) {
3393 memCache.set(
3394 `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
3395 set
3396 );
3397 chunkGraph.addModuleRuntimeRequirements(
3398 module,
3399 runtime,
3400 set,
3401 false
3402 );
3403 } else {
3404 chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
3405 }
3406 }
3407 }
3408 }
3409 }
3410 this.logger.timeEnd("runtime requirements.modules");
3411
3412 this.logger.time("runtime requirements.chunks");
3413 for (const chunk of chunks) {
3414 const set = new Set();
3415 for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
3416 const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
3417 module,
3418 chunk.runtime
3419 );
3420 for (const r of runtimeRequirements) set.add(r);
3421 }
3422 this.hooks.additionalChunkRuntimeRequirements.call(chunk, set, context);
3423
3424 for (const r of set) {
3425 this.hooks.runtimeRequirementInChunk.for(r).call(chunk, set, context);
3426 }
3427
3428 chunkGraph.addChunkRuntimeRequirements(chunk, set);
3429 }
3430 this.logger.timeEnd("runtime requirements.chunks");
3431
3432 this.logger.time("runtime requirements.entries");
3433 for (const treeEntry of chunkGraphEntries) {
3434 const set = new Set();
3435 for (const chunk of treeEntry.getAllReferencedChunks()) {
3436 const runtimeRequirements =
3437 chunkGraph.getChunkRuntimeRequirements(chunk);
3438 for (const r of runtimeRequirements) set.add(r);
3439 }
3440
3441 this.hooks.additionalTreeRuntimeRequirements.call(
3442 treeEntry,
3443 set,
3444 context
3445 );
3446
3447 for (const r of set) {
3448 this.hooks.runtimeRequirementInTree
3449 .for(r)
3450 .call(treeEntry, set, context);
3451 }
3452
3453 chunkGraph.addTreeRuntimeRequirements(treeEntry, set);
3454 }
3455 this.logger.timeEnd("runtime requirements.entries");
3456 }
3457
3458 // TODO webpack 6 make chunkGraph argument non-optional
3459 /**
3460 * @param {Chunk} chunk target chunk
3461 * @param {RuntimeModule} module runtime module
3462 * @param {ChunkGraph} chunkGraph the chunk graph
3463 * @returns {void}
3464 */
3465 addRuntimeModule(chunk, module, chunkGraph = this.chunkGraph) {
3466 // Deprecated ModuleGraph association
3467 if (this._backCompat)
3468 ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
3469
3470 // add it to the list
3471 this.modules.add(module);
3472 this._modules.set(module.identifier(), module);
3473
3474 // connect to the chunk graph
3475 chunkGraph.connectChunkAndModule(chunk, module);
3476 chunkGraph.connectChunkAndRuntimeModule(chunk, module);
3477 if (module.fullHash) {
3478 chunkGraph.addFullHashModuleToChunk(chunk, module);
3479 } else if (module.dependentHash) {
3480 chunkGraph.addDependentHashModuleToChunk(chunk, module);
3481 }
3482
3483 // attach runtime module
3484 module.attach(this, chunk, chunkGraph);
3485
3486 // Setup internals
3487 const exportsInfo = this.moduleGraph.getExportsInfo(module);
3488 exportsInfo.setHasProvideInfo();
3489 if (typeof chunk.runtime === "string") {
3490 exportsInfo.setUsedForSideEffectsOnly(chunk.runtime);
3491 } else if (chunk.runtime === undefined) {
3492 exportsInfo.setUsedForSideEffectsOnly(undefined);
3493 } else {
3494 for (const runtime of chunk.runtime) {
3495 exportsInfo.setUsedForSideEffectsOnly(runtime);
3496 }
3497 }
3498 chunkGraph.addModuleRuntimeRequirements(
3499 module,
3500 chunk.runtime,
3501 new Set([RuntimeGlobals.requireScope])
3502 );
3503
3504 // runtime modules don't need ids
3505 chunkGraph.setModuleId(module, "");
3506
3507 // Call hook
3508 this.hooks.runtimeModule.call(module, chunk);
3509 }
3510
3511 /**
3512 * @param {string | ChunkGroupOptions} groupOptions options for the chunk group
3513 * @param {Module} module the module the references the chunk group
3514 * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
3515 * @param {string} request the request from which the the chunk group is referenced
3516 * @returns {ChunkGroup} the new or existing chunk group
3517 */
3518 addChunkInGroup(groupOptions, module, loc, request) {
3519 if (typeof groupOptions === "string") {
3520 groupOptions = { name: groupOptions };
3521 }
3522 const name = groupOptions.name;
3523
3524 if (name) {
3525 const chunkGroup = this.namedChunkGroups.get(name);
3526 if (chunkGroup !== undefined) {
3527 chunkGroup.addOptions(groupOptions);
3528 if (module) {
3529 chunkGroup.addOrigin(module, loc, request);
3530 }
3531 return chunkGroup;
3532 }
3533 }
3534 const chunkGroup = new ChunkGroup(groupOptions);
3535 if (module) chunkGroup.addOrigin(module, loc, request);
3536 const chunk = this.addChunk(name);
3537
3538 connectChunkGroupAndChunk(chunkGroup, chunk);
3539
3540 this.chunkGroups.push(chunkGroup);
3541 if (name) {
3542 this.namedChunkGroups.set(name, chunkGroup);
3543 }
3544 return chunkGroup;
3545 }
3546
3547 /**
3548 * @param {EntryOptions} options options for the entrypoint
3549 * @param {Module} module the module the references the chunk group
3550 * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
3551 * @param {string} request the request from which the the chunk group is referenced
3552 * @returns {Entrypoint} the new or existing entrypoint
3553 */
3554 addAsyncEntrypoint(options, module, loc, request) {
3555 const name = options.name;
3556 if (name) {
3557 const entrypoint = this.namedChunkGroups.get(name);
3558 if (entrypoint instanceof Entrypoint) {
3559 if (entrypoint !== undefined) {
3560 if (module) {
3561 entrypoint.addOrigin(module, loc, request);
3562 }
3563 return entrypoint;
3564 }
3565 } else if (entrypoint) {
3566 throw new Error(
3567 `Cannot add an async entrypoint with the name '${name}', because there is already an chunk group with this name`
3568 );
3569 }
3570 }
3571 const chunk = this.addChunk(name);
3572 if (options.filename) {
3573 chunk.filenameTemplate = options.filename;
3574 }
3575 const entrypoint = new Entrypoint(options, false);
3576 entrypoint.setRuntimeChunk(chunk);
3577 entrypoint.setEntrypointChunk(chunk);
3578 if (name) {
3579 this.namedChunkGroups.set(name, entrypoint);
3580 }
3581 this.chunkGroups.push(entrypoint);
3582 this.asyncEntrypoints.push(entrypoint);
3583 connectChunkGroupAndChunk(entrypoint, chunk);
3584 if (module) {
3585 entrypoint.addOrigin(module, loc, request);
3586 }
3587 return entrypoint;
3588 }
3589
3590 /**
3591 * This method first looks to see if a name is provided for a new chunk,
3592 * and first looks to see if any named chunks already exist and reuse that chunk instead.
3593 *
3594 * @param {string=} name optional chunk name to be provided
3595 * @returns {Chunk} create a chunk (invoked during seal event)
3596 */
3597 addChunk(name) {
3598 if (name) {
3599 const chunk = this.namedChunks.get(name);
3600 if (chunk !== undefined) {
3601 return chunk;
3602 }
3603 }
3604 const chunk = new Chunk(name, this._backCompat);
3605 this.chunks.add(chunk);
3606 if (this._backCompat)
3607 ChunkGraph.setChunkGraphForChunk(chunk, this.chunkGraph);
3608 if (name) {
3609 this.namedChunks.set(name, chunk);
3610 }
3611 return chunk;
3612 }
3613
3614 /**
3615 * @deprecated
3616 * @param {Module} module module to assign depth
3617 * @returns {void}
3618 */
3619 assignDepth(module) {
3620 const moduleGraph = this.moduleGraph;
3621
3622 const queue = new Set([module]);
3623 let depth;
3624
3625 moduleGraph.setDepth(module, 0);
3626
3627 /**
3628 * @param {Module} module module for processing
3629 * @returns {void}
3630 */
3631 const processModule = module => {
3632 if (!moduleGraph.setDepthIfLower(module, depth)) return;
3633 queue.add(module);
3634 };
3635
3636 for (module of queue) {
3637 queue.delete(module);
3638 depth = moduleGraph.getDepth(module) + 1;
3639
3640 for (const connection of moduleGraph.getOutgoingConnections(module)) {
3641 const refModule = connection.module;
3642 if (refModule) {
3643 processModule(refModule);
3644 }
3645 }
3646 }
3647 }
3648
3649 /**
3650 * @param {Set<Module>} modules module to assign depth
3651 * @returns {void}
3652 */
3653 assignDepths(modules) {
3654 const moduleGraph = this.moduleGraph;
3655
3656 /** @type {Set<Module | number>} */
3657 const queue = new Set(modules);
3658 queue.add(1);
3659 let depth = 0;
3660
3661 let i = 0;
3662 for (const module of queue) {
3663 i++;
3664 if (typeof module === "number") {
3665 depth = module;
3666 if (queue.size === i) return;
3667 queue.add(depth + 1);
3668 } else {
3669 moduleGraph.setDepth(module, depth);
3670 for (const { module: refModule } of moduleGraph.getOutgoingConnections(
3671 module
3672 )) {
3673 if (refModule) {
3674 queue.add(refModule);
3675 }
3676 }
3677 }
3678 }
3679 }
3680
3681 /**
3682 * @param {Dependency} dependency the dependency
3683 * @param {RuntimeSpec} runtime the runtime
3684 * @returns {(string[] | ReferencedExport)[]} referenced exports
3685 */
3686 getDependencyReferencedExports(dependency, runtime) {
3687 const referencedExports = dependency.getReferencedExports(
3688 this.moduleGraph,
3689 runtime
3690 );
3691 return this.hooks.dependencyReferencedExports.call(
3692 referencedExports,
3693 dependency,
3694 runtime
3695 );
3696 }
3697
3698 /**
3699 *
3700 * @param {Module} module module relationship for removal
3701 * @param {DependenciesBlockLike} block //TODO: good description
3702 * @returns {void}
3703 */
3704 removeReasonsOfDependencyBlock(module, block) {
3705 if (block.blocks) {
3706 for (const b of block.blocks) {
3707 this.removeReasonsOfDependencyBlock(module, b);
3708 }
3709 }
3710
3711 if (block.dependencies) {
3712 for (const dep of block.dependencies) {
3713 const originalModule = this.moduleGraph.getModule(dep);
3714 if (originalModule) {
3715 this.moduleGraph.removeConnection(dep);
3716
3717 if (this.chunkGraph) {
3718 for (const chunk of this.chunkGraph.getModuleChunks(
3719 originalModule
3720 )) {
3721 this.patchChunksAfterReasonRemoval(originalModule, chunk);
3722 }
3723 }
3724 }
3725 }
3726 }
3727 }
3728
3729 /**
3730 * @param {Module} module module to patch tie
3731 * @param {Chunk} chunk chunk to patch tie
3732 * @returns {void}
3733 */
3734 patchChunksAfterReasonRemoval(module, chunk) {
3735 if (!module.hasReasons(this.moduleGraph, chunk.runtime)) {
3736 this.removeReasonsOfDependencyBlock(module, module);
3737 }
3738 if (!module.hasReasonForChunk(chunk, this.moduleGraph, this.chunkGraph)) {
3739 if (this.chunkGraph.isModuleInChunk(module, chunk)) {
3740 this.chunkGraph.disconnectChunkAndModule(chunk, module);
3741 this.removeChunkFromDependencies(module, chunk);
3742 }
3743 }
3744 }
3745
3746 /**
3747 *
3748 * @param {DependenciesBlock} block block tie for Chunk
3749 * @param {Chunk} chunk chunk to remove from dep
3750 * @returns {void}
3751 */
3752 removeChunkFromDependencies(block, chunk) {
3753 /**
3754 * @param {Dependency} d dependency to (maybe) patch up
3755 */
3756 const iteratorDependency = d => {
3757 const depModule = this.moduleGraph.getModule(d);
3758 if (!depModule) {
3759 return;
3760 }
3761 this.patchChunksAfterReasonRemoval(depModule, chunk);
3762 };
3763
3764 const blocks = block.blocks;
3765 for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
3766 const asyncBlock = blocks[indexBlock];
3767 const chunkGroup = this.chunkGraph.getBlockChunkGroup(asyncBlock);
3768 // Grab all chunks from the first Block's AsyncDepBlock
3769 const chunks = chunkGroup.chunks;
3770 // For each chunk in chunkGroup
3771 for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
3772 const iteratedChunk = chunks[indexChunk];
3773 chunkGroup.removeChunk(iteratedChunk);
3774 // Recurse
3775 this.removeChunkFromDependencies(block, iteratedChunk);
3776 }
3777 }
3778
3779 if (block.dependencies) {
3780 for (const dep of block.dependencies) iteratorDependency(dep);
3781 }
3782 }
3783
3784 assignRuntimeIds() {
3785 const { chunkGraph } = this;
3786 const processEntrypoint = ep => {
3787 const runtime = ep.options.runtime || ep.name;
3788 const chunk = ep.getRuntimeChunk();
3789 chunkGraph.setRuntimeId(runtime, chunk.id);
3790 };
3791 for (const ep of this.entrypoints.values()) {
3792 processEntrypoint(ep);
3793 }
3794 for (const ep of this.asyncEntrypoints) {
3795 processEntrypoint(ep);
3796 }
3797 }
3798
3799 sortItemsWithChunkIds() {
3800 for (const chunkGroup of this.chunkGroups) {
3801 chunkGroup.sortItems();
3802 }
3803
3804 this.errors.sort(compareErrors);
3805 this.warnings.sort(compareErrors);
3806 this.children.sort(byNameOrHash);
3807 }
3808
3809 summarizeDependencies() {
3810 for (
3811 let indexChildren = 0;
3812 indexChildren < this.children.length;
3813 indexChildren++
3814 ) {
3815 const child = this.children[indexChildren];
3816
3817 this.fileDependencies.addAll(child.fileDependencies);
3818 this.contextDependencies.addAll(child.contextDependencies);
3819 this.missingDependencies.addAll(child.missingDependencies);
3820 this.buildDependencies.addAll(child.buildDependencies);
3821 }
3822
3823 for (const module of this.modules) {
3824 module.addCacheDependencies(
3825 this.fileDependencies,
3826 this.contextDependencies,
3827 this.missingDependencies,
3828 this.buildDependencies
3829 );
3830 }
3831 }
3832
3833 createModuleHashes() {
3834 let statModulesHashed = 0;
3835 let statModulesFromCache = 0;
3836 const { chunkGraph, runtimeTemplate, moduleMemCaches2 } = this;
3837 const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
3838 for (const module of this.modules) {
3839 const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
3840 for (const runtime of chunkGraph.getModuleRuntimes(module)) {
3841 if (memCache) {
3842 const digest = memCache.get(`moduleHash-${getRuntimeKey(runtime)}`);
3843 if (digest !== undefined) {
3844 chunkGraph.setModuleHashes(
3845 module,
3846 runtime,
3847 digest,
3848 digest.substr(0, hashDigestLength)
3849 );
3850 statModulesFromCache++;
3851 continue;
3852 }
3853 }
3854 statModulesHashed++;
3855 const digest = this._createModuleHash(
3856 module,
3857 chunkGraph,
3858 runtime,
3859 hashFunction,
3860 runtimeTemplate,
3861 hashDigest,
3862 hashDigestLength
3863 );
3864 if (memCache) {
3865 memCache.set(`moduleHash-${getRuntimeKey(runtime)}`, digest);
3866 }
3867 }
3868 }
3869 this.logger.log(
3870 `${statModulesHashed} modules hashed, ${statModulesFromCache} from cache (${
3871 Math.round(
3872 (100 * (statModulesHashed + statModulesFromCache)) / this.modules.size
3873 ) / 100
3874 } variants per module in average)`
3875 );
3876 }
3877
3878 _createModuleHash(
3879 module,
3880 chunkGraph,
3881 runtime,
3882 hashFunction,
3883 runtimeTemplate,
3884 hashDigest,
3885 hashDigestLength
3886 ) {
3887 const moduleHash = createHash(hashFunction);
3888 module.updateHash(moduleHash, {
3889 chunkGraph,
3890 runtime,
3891 runtimeTemplate
3892 });
3893 const moduleHashDigest = /** @type {string} */ (
3894 moduleHash.digest(hashDigest)
3895 );
3896 chunkGraph.setModuleHashes(
3897 module,
3898 runtime,
3899 moduleHashDigest,
3900 moduleHashDigest.substr(0, hashDigestLength)
3901 );
3902 return moduleHashDigest;
3903 }
3904
3905 createHash() {
3906 this.logger.time("hashing: initialize hash");
3907 const chunkGraph = this.chunkGraph;
3908 const runtimeTemplate = this.runtimeTemplate;
3909 const outputOptions = this.outputOptions;
3910 const hashFunction = outputOptions.hashFunction;
3911 const hashDigest = outputOptions.hashDigest;
3912 const hashDigestLength = outputOptions.hashDigestLength;
3913 const hash = createHash(hashFunction);
3914 if (outputOptions.hashSalt) {
3915 hash.update(outputOptions.hashSalt);
3916 }
3917 this.logger.timeEnd("hashing: initialize hash");
3918 if (this.children.length > 0) {
3919 this.logger.time("hashing: hash child compilations");
3920 for (const child of this.children) {
3921 hash.update(child.hash);
3922 }
3923 this.logger.timeEnd("hashing: hash child compilations");
3924 }
3925 if (this.warnings.length > 0) {
3926 this.logger.time("hashing: hash warnings");
3927 for (const warning of this.warnings) {
3928 hash.update(`${warning.message}`);
3929 }
3930 this.logger.timeEnd("hashing: hash warnings");
3931 }
3932 if (this.errors.length > 0) {
3933 this.logger.time("hashing: hash errors");
3934 for (const error of this.errors) {
3935 hash.update(`${error.message}`);
3936 }
3937 this.logger.timeEnd("hashing: hash errors");
3938 }
3939
3940 this.logger.time("hashing: sort chunks");
3941 /*
3942 * all non-runtime chunks need to be hashes first,
3943 * since runtime chunk might use their hashes.
3944 * runtime chunks need to be hashed in the correct order
3945 * since they may depend on each other (for async entrypoints).
3946 * So we put all non-runtime chunks first and hash them in any order.
3947 * And order runtime chunks according to referenced between each other.
3948 * Chunks need to be in deterministic order since we add hashes to full chunk
3949 * during these hashing.
3950 */
3951 /** @type {Chunk[]} */
3952 const unorderedRuntimeChunks = [];
3953 /** @type {Chunk[]} */
3954 const otherChunks = [];
3955 for (const c of this.chunks) {
3956 if (c.hasRuntime()) {
3957 unorderedRuntimeChunks.push(c);
3958 } else {
3959 otherChunks.push(c);
3960 }
3961 }
3962 unorderedRuntimeChunks.sort(byId);
3963 otherChunks.sort(byId);
3964
3965 /** @typedef {{ chunk: Chunk, referencedBy: RuntimeChunkInfo[], remaining: number }} RuntimeChunkInfo */
3966 /** @type {Map<Chunk, RuntimeChunkInfo>} */
3967 const runtimeChunksMap = new Map();
3968 for (const chunk of unorderedRuntimeChunks) {
3969 runtimeChunksMap.set(chunk, {
3970 chunk,
3971 referencedBy: [],
3972 remaining: 0
3973 });
3974 }
3975 let remaining = 0;
3976 for (const info of runtimeChunksMap.values()) {
3977 for (const other of new Set(
3978 Array.from(info.chunk.getAllReferencedAsyncEntrypoints()).map(
3979 e => e.chunks[e.chunks.length - 1]
3980 )
3981 )) {
3982 const otherInfo = runtimeChunksMap.get(other);
3983 otherInfo.referencedBy.push(info);
3984 info.remaining++;
3985 remaining++;
3986 }
3987 }
3988 /** @type {Chunk[]} */
3989 const runtimeChunks = [];
3990 for (const info of runtimeChunksMap.values()) {
3991 if (info.remaining === 0) {
3992 runtimeChunks.push(info.chunk);
3993 }
3994 }
3995 // If there are any references between chunks
3996 // make sure to follow these chains
3997 if (remaining > 0) {
3998 const readyChunks = [];
3999 for (const chunk of runtimeChunks) {
4000 const hasFullHashModules =
4001 chunkGraph.getNumberOfChunkFullHashModules(chunk) !== 0;
4002 const info = runtimeChunksMap.get(chunk);
4003 for (const otherInfo of info.referencedBy) {
4004 if (hasFullHashModules) {
4005 chunkGraph.upgradeDependentToFullHashModules(otherInfo.chunk);
4006 }
4007 remaining--;
4008 if (--otherInfo.remaining === 0) {
4009 readyChunks.push(otherInfo.chunk);
4010 }
4011 }
4012 if (readyChunks.length > 0) {
4013 // This ensures deterministic ordering, since referencedBy is non-deterministic
4014 readyChunks.sort(byId);
4015 for (const c of readyChunks) runtimeChunks.push(c);
4016 readyChunks.length = 0;
4017 }
4018 }
4019 }
4020 // If there are still remaining references we have cycles and want to create a warning
4021 if (remaining > 0) {
4022 let circularRuntimeChunkInfo = [];
4023 for (const info of runtimeChunksMap.values()) {
4024 if (info.remaining !== 0) {
4025 circularRuntimeChunkInfo.push(info);
4026 }
4027 }
4028 circularRuntimeChunkInfo.sort(compareSelect(i => i.chunk, byId));
4029 const err =
4030 new WebpackError(`Circular dependency between chunks with runtime (${Array.from(
4031 circularRuntimeChunkInfo,
4032 c => c.chunk.name || c.chunk.id
4033 ).join(", ")})
4034This prevents using hashes of each other and should be avoided.`);
4035 err.chunk = circularRuntimeChunkInfo[0].chunk;
4036 this.warnings.push(err);
4037 for (const i of circularRuntimeChunkInfo) runtimeChunks.push(i.chunk);
4038 }
4039 this.logger.timeEnd("hashing: sort chunks");
4040
4041 const fullHashChunks = new Set();
4042 /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */
4043 const codeGenerationJobs = [];
4044 /** @type {Map<string, Map<Module, {module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}>>} */
4045 const codeGenerationJobsMap = new Map();
4046
4047 const processChunk = chunk => {
4048 // Last minute module hash generation for modules that depend on chunk hashes
4049 this.logger.time("hashing: hash runtime modules");
4050 const runtime = chunk.runtime;
4051 for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
4052 if (!chunkGraph.hasModuleHashes(module, runtime)) {
4053 const hash = this._createModuleHash(
4054 module,
4055 chunkGraph,
4056 runtime,
4057 hashFunction,
4058 runtimeTemplate,
4059 hashDigest,
4060 hashDigestLength
4061 );
4062 let hashMap = codeGenerationJobsMap.get(hash);
4063 if (hashMap) {
4064 const moduleJob = hashMap.get(module);
4065 if (moduleJob) {
4066 moduleJob.runtimes.push(runtime);
4067 continue;
4068 }
4069 } else {
4070 hashMap = new Map();
4071 codeGenerationJobsMap.set(hash, hashMap);
4072 }
4073 const job = {
4074 module,
4075 hash,
4076 runtime,
4077 runtimes: [runtime]
4078 };
4079 hashMap.set(module, job);
4080 codeGenerationJobs.push(job);
4081 }
4082 }
4083 this.logger.timeAggregate("hashing: hash runtime modules");
4084 this.logger.time("hashing: hash chunks");
4085 const chunkHash = createHash(hashFunction);
4086 try {
4087 if (outputOptions.hashSalt) {
4088 chunkHash.update(outputOptions.hashSalt);
4089 }
4090 chunk.updateHash(chunkHash, chunkGraph);
4091 this.hooks.chunkHash.call(chunk, chunkHash, {
4092 chunkGraph,
4093 moduleGraph: this.moduleGraph,
4094 runtimeTemplate: this.runtimeTemplate
4095 });
4096 const chunkHashDigest = /** @type {string} */ (
4097 chunkHash.digest(hashDigest)
4098 );
4099 hash.update(chunkHashDigest);
4100 chunk.hash = chunkHashDigest;
4101 chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
4102 const fullHashModules =
4103 chunkGraph.getChunkFullHashModulesIterable(chunk);
4104 if (fullHashModules) {
4105 fullHashChunks.add(chunk);
4106 } else {
4107 this.hooks.contentHash.call(chunk);
4108 }
4109 } catch (err) {
4110 this.errors.push(new ChunkRenderError(chunk, "", err));
4111 }
4112 this.logger.timeAggregate("hashing: hash chunks");
4113 };
4114 otherChunks.forEach(processChunk);
4115 for (const chunk of runtimeChunks) processChunk(chunk);
4116
4117 this.logger.timeAggregateEnd("hashing: hash runtime modules");
4118 this.logger.timeAggregateEnd("hashing: hash chunks");
4119 this.logger.time("hashing: hash digest");
4120 this.hooks.fullHash.call(hash);
4121 this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
4122 this.hash = this.fullHash.substr(0, hashDigestLength);
4123 this.logger.timeEnd("hashing: hash digest");
4124
4125 this.logger.time("hashing: process full hash modules");
4126 for (const chunk of fullHashChunks) {
4127 for (const module of chunkGraph.getChunkFullHashModulesIterable(chunk)) {
4128 const moduleHash = createHash(hashFunction);
4129 module.updateHash(moduleHash, {
4130 chunkGraph,
4131 runtime: chunk.runtime,
4132 runtimeTemplate
4133 });
4134 const moduleHashDigest = /** @type {string} */ (
4135 moduleHash.digest(hashDigest)
4136 );
4137 const oldHash = chunkGraph.getModuleHash(module, chunk.runtime);
4138 chunkGraph.setModuleHashes(
4139 module,
4140 chunk.runtime,
4141 moduleHashDigest,
4142 moduleHashDigest.substr(0, hashDigestLength)
4143 );
4144 codeGenerationJobsMap.get(oldHash).get(module).hash = moduleHashDigest;
4145 }
4146 const chunkHash = createHash(hashFunction);
4147 chunkHash.update(chunk.hash);
4148 chunkHash.update(this.hash);
4149 const chunkHashDigest = /** @type {string} */ (
4150 chunkHash.digest(hashDigest)
4151 );
4152 chunk.hash = chunkHashDigest;
4153 chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
4154 this.hooks.contentHash.call(chunk);
4155 }
4156 this.logger.timeEnd("hashing: process full hash modules");
4157 return codeGenerationJobs;
4158 }
4159
4160 /**
4161 * @param {string} file file name
4162 * @param {Source} source asset source
4163 * @param {AssetInfo} assetInfo extra asset information
4164 * @returns {void}
4165 */
4166 emitAsset(file, source, assetInfo = {}) {
4167 if (this.assets[file]) {
4168 if (!isSourceEqual(this.assets[file], source)) {
4169 this.errors.push(
4170 new WebpackError(
4171 `Conflict: Multiple assets emit different content to the same filename ${file}`
4172 )
4173 );
4174 this.assets[file] = source;
4175 this._setAssetInfo(file, assetInfo);
4176 return;
4177 }
4178 const oldInfo = this.assetsInfo.get(file);
4179 const newInfo = Object.assign({}, oldInfo, assetInfo);
4180 this._setAssetInfo(file, newInfo, oldInfo);
4181 return;
4182 }
4183 this.assets[file] = source;
4184 this._setAssetInfo(file, assetInfo, undefined);
4185 }
4186
4187 _setAssetInfo(file, newInfo, oldInfo = this.assetsInfo.get(file)) {
4188 if (newInfo === undefined) {
4189 this.assetsInfo.delete(file);
4190 } else {
4191 this.assetsInfo.set(file, newInfo);
4192 }
4193 const oldRelated = oldInfo && oldInfo.related;
4194 const newRelated = newInfo && newInfo.related;
4195 if (oldRelated) {
4196 for (const key of Object.keys(oldRelated)) {
4197 const remove = name => {
4198 const relatedIn = this._assetsRelatedIn.get(name);
4199 if (relatedIn === undefined) return;
4200 const entry = relatedIn.get(key);
4201 if (entry === undefined) return;
4202 entry.delete(file);
4203 if (entry.size !== 0) return;
4204 relatedIn.delete(key);
4205 if (relatedIn.size === 0) this._assetsRelatedIn.delete(name);
4206 };
4207 const entry = oldRelated[key];
4208 if (Array.isArray(entry)) {
4209 entry.forEach(remove);
4210 } else if (entry) {
4211 remove(entry);
4212 }
4213 }
4214 }
4215 if (newRelated) {
4216 for (const key of Object.keys(newRelated)) {
4217 const add = name => {
4218 let relatedIn = this._assetsRelatedIn.get(name);
4219 if (relatedIn === undefined) {
4220 this._assetsRelatedIn.set(name, (relatedIn = new Map()));
4221 }
4222 let entry = relatedIn.get(key);
4223 if (entry === undefined) {
4224 relatedIn.set(key, (entry = new Set()));
4225 }
4226 entry.add(file);
4227 };
4228 const entry = newRelated[key];
4229 if (Array.isArray(entry)) {
4230 entry.forEach(add);
4231 } else if (entry) {
4232 add(entry);
4233 }
4234 }
4235 }
4236 }
4237
4238 /**
4239 * @param {string} file file name
4240 * @param {Source | function(Source): Source} newSourceOrFunction new asset source or function converting old to new
4241 * @param {AssetInfo | function(AssetInfo | undefined): AssetInfo} assetInfoUpdateOrFunction new asset info or function converting old to new
4242 */
4243 updateAsset(
4244 file,
4245 newSourceOrFunction,
4246 assetInfoUpdateOrFunction = undefined
4247 ) {
4248 if (!this.assets[file]) {
4249 throw new Error(
4250 `Called Compilation.updateAsset for not existing filename ${file}`
4251 );
4252 }
4253 if (typeof newSourceOrFunction === "function") {
4254 this.assets[file] = newSourceOrFunction(this.assets[file]);
4255 } else {
4256 this.assets[file] = newSourceOrFunction;
4257 }
4258 if (assetInfoUpdateOrFunction !== undefined) {
4259 const oldInfo = this.assetsInfo.get(file) || EMPTY_ASSET_INFO;
4260 if (typeof assetInfoUpdateOrFunction === "function") {
4261 this._setAssetInfo(file, assetInfoUpdateOrFunction(oldInfo), oldInfo);
4262 } else {
4263 this._setAssetInfo(
4264 file,
4265 cachedCleverMerge(oldInfo, assetInfoUpdateOrFunction),
4266 oldInfo
4267 );
4268 }
4269 }
4270 }
4271
4272 renameAsset(file, newFile) {
4273 const source = this.assets[file];
4274 if (!source) {
4275 throw new Error(
4276 `Called Compilation.renameAsset for not existing filename ${file}`
4277 );
4278 }
4279 if (this.assets[newFile]) {
4280 if (!isSourceEqual(this.assets[file], source)) {
4281 this.errors.push(
4282 new WebpackError(
4283 `Conflict: Called Compilation.renameAsset for already existing filename ${newFile} with different content`
4284 )
4285 );
4286 }
4287 }
4288 const assetInfo = this.assetsInfo.get(file);
4289 // Update related in all other assets
4290 const relatedInInfo = this._assetsRelatedIn.get(file);
4291 if (relatedInInfo) {
4292 for (const [key, assets] of relatedInInfo) {
4293 for (const name of assets) {
4294 const info = this.assetsInfo.get(name);
4295 if (!info) continue;
4296 const related = info.related;
4297 if (!related) continue;
4298 const entry = related[key];
4299 let newEntry;
4300 if (Array.isArray(entry)) {
4301 newEntry = entry.map(x => (x === file ? newFile : x));
4302 } else if (entry === file) {
4303 newEntry = newFile;
4304 } else continue;
4305 this.assetsInfo.set(name, {
4306 ...info,
4307 related: {
4308 ...related,
4309 [key]: newEntry
4310 }
4311 });
4312 }
4313 }
4314 }
4315 this._setAssetInfo(file, undefined, assetInfo);
4316 this._setAssetInfo(newFile, assetInfo);
4317 delete this.assets[file];
4318 this.assets[newFile] = source;
4319 for (const chunk of this.chunks) {
4320 {
4321 const size = chunk.files.size;
4322 chunk.files.delete(file);
4323 if (size !== chunk.files.size) {
4324 chunk.files.add(newFile);
4325 }
4326 }
4327 {
4328 const size = chunk.auxiliaryFiles.size;
4329 chunk.auxiliaryFiles.delete(file);
4330 if (size !== chunk.auxiliaryFiles.size) {
4331 chunk.auxiliaryFiles.add(newFile);
4332 }
4333 }
4334 }
4335 }
4336
4337 /**
4338 * @param {string} file file name
4339 */
4340 deleteAsset(file) {
4341 if (!this.assets[file]) {
4342 return;
4343 }
4344 delete this.assets[file];
4345 const assetInfo = this.assetsInfo.get(file);
4346 this._setAssetInfo(file, undefined, assetInfo);
4347 const related = assetInfo && assetInfo.related;
4348 if (related) {
4349 for (const key of Object.keys(related)) {
4350 const checkUsedAndDelete = file => {
4351 if (!this._assetsRelatedIn.has(file)) {
4352 this.deleteAsset(file);
4353 }
4354 };
4355 const items = related[key];
4356 if (Array.isArray(items)) {
4357 items.forEach(checkUsedAndDelete);
4358 } else if (items) {
4359 checkUsedAndDelete(items);
4360 }
4361 }
4362 }
4363 // TODO If this becomes a performance problem
4364 // store a reverse mapping from asset to chunk
4365 for (const chunk of this.chunks) {
4366 chunk.files.delete(file);
4367 chunk.auxiliaryFiles.delete(file);
4368 }
4369 }
4370
4371 getAssets() {
4372 /** @type {Readonly<Asset>[]} */
4373 const array = [];
4374 for (const assetName of Object.keys(this.assets)) {
4375 if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) {
4376 array.push({
4377 name: assetName,
4378 source: this.assets[assetName],
4379 info: this.assetsInfo.get(assetName) || EMPTY_ASSET_INFO
4380 });
4381 }
4382 }
4383 return array;
4384 }
4385
4386 /**
4387 * @param {string} name the name of the asset
4388 * @returns {Readonly<Asset> | undefined} the asset or undefined when not found
4389 */
4390 getAsset(name) {
4391 if (!Object.prototype.hasOwnProperty.call(this.assets, name))
4392 return undefined;
4393 return {
4394 name,
4395 source: this.assets[name],
4396 info: this.assetsInfo.get(name) || EMPTY_ASSET_INFO
4397 };
4398 }
4399
4400 clearAssets() {
4401 for (const chunk of this.chunks) {
4402 chunk.files.clear();
4403 chunk.auxiliaryFiles.clear();
4404 }
4405 }
4406
4407 createModuleAssets() {
4408 const { chunkGraph } = this;
4409 for (const module of this.modules) {
4410 if (module.buildInfo.assets) {
4411 const assetsInfo = module.buildInfo.assetsInfo;
4412 for (const assetName of Object.keys(module.buildInfo.assets)) {
4413 const fileName = this.getPath(assetName, {
4414 chunkGraph: this.chunkGraph,
4415 module
4416 });
4417 for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
4418 chunk.auxiliaryFiles.add(fileName);
4419 }
4420 this.emitAsset(
4421 fileName,
4422 module.buildInfo.assets[assetName],
4423 assetsInfo ? assetsInfo.get(assetName) : undefined
4424 );
4425 this.hooks.moduleAsset.call(module, fileName);
4426 }
4427 }
4428 }
4429 }
4430
4431 /**
4432 * @param {RenderManifestOptions} options options object
4433 * @returns {RenderManifestEntry[]} manifest entries
4434 */
4435 getRenderManifest(options) {
4436 return this.hooks.renderManifest.call([], options);
4437 }
4438
4439 /**
4440 * @param {Callback} callback signals when the call finishes
4441 * @returns {void}
4442 */
4443 createChunkAssets(callback) {
4444 const outputOptions = this.outputOptions;
4445 const cachedSourceMap = new WeakMap();
4446 /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
4447 const alreadyWrittenFiles = new Map();
4448
4449 asyncLib.forEachLimit(
4450 this.chunks,
4451 15,
4452 (chunk, callback) => {
4453 /** @type {RenderManifestEntry[]} */
4454 let manifest;
4455 try {
4456 manifest = this.getRenderManifest({
4457 chunk,
4458 hash: this.hash,
4459 fullHash: this.fullHash,
4460 outputOptions,
4461 codeGenerationResults: this.codeGenerationResults,
4462 moduleTemplates: this.moduleTemplates,
4463 dependencyTemplates: this.dependencyTemplates,
4464 chunkGraph: this.chunkGraph,
4465 moduleGraph: this.moduleGraph,
4466 runtimeTemplate: this.runtimeTemplate
4467 });
4468 } catch (err) {
4469 this.errors.push(new ChunkRenderError(chunk, "", err));
4470 return callback();
4471 }
4472 asyncLib.forEach(
4473 manifest,
4474 (fileManifest, callback) => {
4475 const ident = fileManifest.identifier;
4476 const usedHash = fileManifest.hash;
4477
4478 const assetCacheItem = this._assetsCache.getItemCache(
4479 ident,
4480 usedHash
4481 );
4482
4483 assetCacheItem.get((err, sourceFromCache) => {
4484 /** @type {string | function(PathData, AssetInfo=): string} */
4485 let filenameTemplate;
4486 /** @type {string} */
4487 let file;
4488 /** @type {AssetInfo} */
4489 let assetInfo;
4490
4491 let inTry = true;
4492 const errorAndCallback = err => {
4493 const filename =
4494 file ||
4495 (typeof file === "string"
4496 ? file
4497 : typeof filenameTemplate === "string"
4498 ? filenameTemplate
4499 : "");
4500
4501 this.errors.push(new ChunkRenderError(chunk, filename, err));
4502 inTry = false;
4503 return callback();
4504 };
4505
4506 try {
4507 if ("filename" in fileManifest) {
4508 file = fileManifest.filename;
4509 assetInfo = fileManifest.info;
4510 } else {
4511 filenameTemplate = fileManifest.filenameTemplate;
4512 const pathAndInfo = this.getPathWithInfo(
4513 filenameTemplate,
4514 fileManifest.pathOptions
4515 );
4516 file = pathAndInfo.path;
4517 assetInfo = fileManifest.info
4518 ? {
4519 ...pathAndInfo.info,
4520 ...fileManifest.info
4521 }
4522 : pathAndInfo.info;
4523 }
4524
4525 if (err) {
4526 return errorAndCallback(err);
4527 }
4528
4529 let source = sourceFromCache;
4530
4531 // check if the same filename was already written by another chunk
4532 const alreadyWritten = alreadyWrittenFiles.get(file);
4533 if (alreadyWritten !== undefined) {
4534 if (alreadyWritten.hash !== usedHash) {
4535 inTry = false;
4536 return callback(
4537 new WebpackError(
4538 `Conflict: Multiple chunks emit assets to the same filename ${file}` +
4539 ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
4540 )
4541 );
4542 } else {
4543 source = alreadyWritten.source;
4544 }
4545 } else if (!source) {
4546 // render the asset
4547 source = fileManifest.render();
4548
4549 // Ensure that source is a cached source to avoid additional cost because of repeated access
4550 if (!(source instanceof CachedSource)) {
4551 const cacheEntry = cachedSourceMap.get(source);
4552 if (cacheEntry) {
4553 source = cacheEntry;
4554 } else {
4555 const cachedSource = new CachedSource(source);
4556 cachedSourceMap.set(source, cachedSource);
4557 source = cachedSource;
4558 }
4559 }
4560 }
4561 this.emitAsset(file, source, assetInfo);
4562 if (fileManifest.auxiliary) {
4563 chunk.auxiliaryFiles.add(file);
4564 } else {
4565 chunk.files.add(file);
4566 }
4567 this.hooks.chunkAsset.call(chunk, file);
4568 alreadyWrittenFiles.set(file, {
4569 hash: usedHash,
4570 source,
4571 chunk
4572 });
4573 if (source !== sourceFromCache) {
4574 assetCacheItem.store(source, err => {
4575 if (err) return errorAndCallback(err);
4576 inTry = false;
4577 return callback();
4578 });
4579 } else {
4580 inTry = false;
4581 callback();
4582 }
4583 } catch (err) {
4584 if (!inTry) throw err;
4585 errorAndCallback(err);
4586 }
4587 });
4588 },
4589 callback
4590 );
4591 },
4592 callback
4593 );
4594 }
4595
4596 /**
4597 * @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
4598 * @param {PathData} data context data
4599 * @returns {string} interpolated path
4600 */
4601 getPath(filename, data = {}) {
4602 if (!data.hash) {
4603 data = {
4604 hash: this.hash,
4605 ...data
4606 };
4607 }
4608 return this.getAssetPath(filename, data);
4609 }
4610
4611 /**
4612 * @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
4613 * @param {PathData} data context data
4614 * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
4615 */
4616 getPathWithInfo(filename, data = {}) {
4617 if (!data.hash) {
4618 data = {
4619 hash: this.hash,
4620 ...data
4621 };
4622 }
4623 return this.getAssetPathWithInfo(filename, data);
4624 }
4625
4626 /**
4627 * @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
4628 * @param {PathData} data context data
4629 * @returns {string} interpolated path
4630 */
4631 getAssetPath(filename, data) {
4632 return this.hooks.assetPath.call(
4633 typeof filename === "function" ? filename(data) : filename,
4634 data,
4635 undefined
4636 );
4637 }
4638
4639 /**
4640 * @param {string | function(PathData, AssetInfo=): string} filename used to get asset path with hash
4641 * @param {PathData} data context data
4642 * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
4643 */
4644 getAssetPathWithInfo(filename, data) {
4645 const assetInfo = {};
4646 // TODO webpack 5: refactor assetPath hook to receive { path, info } object
4647 const newPath = this.hooks.assetPath.call(
4648 typeof filename === "function" ? filename(data, assetInfo) : filename,
4649 data,
4650 assetInfo
4651 );
4652 return { path: newPath, info: assetInfo };
4653 }
4654
4655 getWarnings() {
4656 return this.hooks.processWarnings.call(this.warnings);
4657 }
4658
4659 getErrors() {
4660 return this.hooks.processErrors.call(this.errors);
4661 }
4662
4663 /**
4664 * This function allows you to run another instance of webpack inside of webpack however as
4665 * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
4666 * from parent (or top level compiler) and creates a child Compilation
4667 *
4668 * @param {string} name name of the child compiler
4669 * @param {OutputOptions=} outputOptions // Need to convert config schema to types for this
4670 * @param {Array<WebpackPluginInstance | WebpackPluginFunction>=} plugins webpack plugins that will be applied
4671 * @returns {Compiler} creates a child Compiler instance
4672 */
4673 createChildCompiler(name, outputOptions, plugins) {
4674 const idx = this.childrenCounters[name] || 0;
4675 this.childrenCounters[name] = idx + 1;
4676 return this.compiler.createChildCompiler(
4677 this,
4678 name,
4679 idx,
4680 outputOptions,
4681 plugins
4682 );
4683 }
4684
4685 /**
4686 * @param {Module} module the module
4687 * @param {ExecuteModuleOptions} options options
4688 * @param {ExecuteModuleCallback} callback callback
4689 */
4690 executeModule(module, options, callback) {
4691 // Aggregate all referenced modules and ensure they are ready
4692 const modules = new Set([module]);
4693 processAsyncTree(
4694 modules,
4695 10,
4696 /**
4697 * @param {Module} module the module
4698 * @param {function(Module): void} push push more jobs
4699 * @param {Callback} callback callback
4700 * @returns {void}
4701 */
4702 (module, push, callback) => {
4703 this.buildQueue.waitFor(module, err => {
4704 if (err) return callback(err);
4705 this.processDependenciesQueue.waitFor(module, err => {
4706 if (err) return callback(err);
4707 for (const { module: m } of this.moduleGraph.getOutgoingConnections(
4708 module
4709 )) {
4710 const size = modules.size;
4711 modules.add(m);
4712 if (modules.size !== size) push(m);
4713 }
4714 callback();
4715 });
4716 });
4717 },
4718 err => {
4719 if (err) return callback(err);
4720
4721 // Create new chunk graph, chunk and entrypoint for the build time execution
4722 const chunkGraph = new ChunkGraph(
4723 this.moduleGraph,
4724 this.outputOptions.hashFunction
4725 );
4726 const runtime = "build time";
4727 const { hashFunction, hashDigest, hashDigestLength } =
4728 this.outputOptions;
4729 const runtimeTemplate = this.runtimeTemplate;
4730
4731 const chunk = new Chunk("build time chunk", this._backCompat);
4732 chunk.id = chunk.name;
4733 chunk.ids = [chunk.id];
4734 chunk.runtime = runtime;
4735
4736 const entrypoint = new Entrypoint({
4737 runtime,
4738 chunkLoading: false,
4739 ...options.entryOptions
4740 });
4741 chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
4742 connectChunkGroupAndChunk(entrypoint, chunk);
4743 entrypoint.setRuntimeChunk(chunk);
4744 entrypoint.setEntrypointChunk(chunk);
4745
4746 const chunks = new Set([chunk]);
4747
4748 // Assign ids to modules and modules to the chunk
4749 for (const module of modules) {
4750 const id = module.identifier();
4751 chunkGraph.setModuleId(module, id);
4752 chunkGraph.connectChunkAndModule(chunk, module);
4753 }
4754
4755 // Hash modules
4756 for (const module of modules) {
4757 this._createModuleHash(
4758 module,
4759 chunkGraph,
4760 runtime,
4761 hashFunction,
4762 runtimeTemplate,
4763 hashDigest,
4764 hashDigestLength
4765 );
4766 }
4767
4768 const codeGenerationResults = new CodeGenerationResults(
4769 this.outputOptions.hashFunction
4770 );
4771 /** @type {WebpackError[]} */
4772 const errors = [];
4773 /**
4774 * @param {Module} module the module
4775 * @param {Callback} callback callback
4776 * @returns {void}
4777 */
4778 const codeGen = (module, callback) => {
4779 this._codeGenerationModule(
4780 module,
4781 runtime,
4782 [runtime],
4783 chunkGraph.getModuleHash(module, runtime),
4784 this.dependencyTemplates,
4785 chunkGraph,
4786 this.moduleGraph,
4787 runtimeTemplate,
4788 errors,
4789 codeGenerationResults,
4790 (err, codeGenerated) => {
4791 callback(err);
4792 }
4793 );
4794 };
4795
4796 const reportErrors = () => {
4797 if (errors.length > 0) {
4798 errors.sort(
4799 compareSelect(err => err.module, compareModulesByIdentifier)
4800 );
4801 for (const error of errors) {
4802 this.errors.push(error);
4803 }
4804 errors.length = 0;
4805 }
4806 };
4807
4808 // Generate code for all aggregated modules
4809 asyncLib.eachLimit(modules, 10, codeGen, err => {
4810 if (err) return callback(err);
4811 reportErrors();
4812
4813 // for backward-compat temporary set the chunk graph
4814 // TODO webpack 6
4815 const old = this.chunkGraph;
4816 this.chunkGraph = chunkGraph;
4817 this.processRuntimeRequirements({
4818 chunkGraph,
4819 modules,
4820 chunks,
4821 codeGenerationResults,
4822 chunkGraphEntries: chunks
4823 });
4824 this.chunkGraph = old;
4825
4826 const runtimeModules =
4827 chunkGraph.getChunkRuntimeModulesIterable(chunk);
4828
4829 // Hash runtime modules
4830 for (const module of runtimeModules) {
4831 modules.add(module);
4832 this._createModuleHash(
4833 module,
4834 chunkGraph,
4835 runtime,
4836 hashFunction,
4837 runtimeTemplate,
4838 hashDigest,
4839 hashDigestLength
4840 );
4841 }
4842
4843 // Generate code for all runtime modules
4844 asyncLib.eachLimit(runtimeModules, 10, codeGen, err => {
4845 if (err) return callback(err);
4846 reportErrors();
4847
4848 /** @type {Map<Module, ExecuteModuleArgument>} */
4849 const moduleArgumentsMap = new Map();
4850 /** @type {Map<string, ExecuteModuleArgument>} */
4851 const moduleArgumentsById = new Map();
4852
4853 /** @type {ExecuteModuleResult["fileDependencies"]} */
4854 const fileDependencies = new LazySet();
4855 /** @type {ExecuteModuleResult["contextDependencies"]} */
4856 const contextDependencies = new LazySet();
4857 /** @type {ExecuteModuleResult["missingDependencies"]} */
4858 const missingDependencies = new LazySet();
4859 /** @type {ExecuteModuleResult["buildDependencies"]} */
4860 const buildDependencies = new LazySet();
4861
4862 /** @type {ExecuteModuleResult["assets"]} */
4863 const assets = new Map();
4864
4865 let cacheable = true;
4866
4867 /** @type {ExecuteModuleContext} */
4868 const context = {
4869 assets,
4870 __webpack_require__: undefined,
4871 chunk,
4872 chunkGraph
4873 };
4874
4875 // Prepare execution
4876 asyncLib.eachLimit(
4877 modules,
4878 10,
4879 (module, callback) => {
4880 const codeGenerationResult = codeGenerationResults.get(
4881 module,
4882 runtime
4883 );
4884 /** @type {ExecuteModuleArgument} */
4885 const moduleArgument = {
4886 module,
4887 codeGenerationResult,
4888 preparedInfo: undefined,
4889 moduleObject: undefined
4890 };
4891 moduleArgumentsMap.set(module, moduleArgument);
4892 moduleArgumentsById.set(module.identifier(), moduleArgument);
4893 module.addCacheDependencies(
4894 fileDependencies,
4895 contextDependencies,
4896 missingDependencies,
4897 buildDependencies
4898 );
4899 if (module.buildInfo.cacheable === false) {
4900 cacheable = false;
4901 }
4902 if (module.buildInfo && module.buildInfo.assets) {
4903 const { assets: moduleAssets, assetsInfo } = module.buildInfo;
4904 for (const assetName of Object.keys(moduleAssets)) {
4905 assets.set(assetName, {
4906 source: moduleAssets[assetName],
4907 info: assetsInfo ? assetsInfo.get(assetName) : undefined
4908 });
4909 }
4910 }
4911 this.hooks.prepareModuleExecution.callAsync(
4912 moduleArgument,
4913 context,
4914 callback
4915 );
4916 },
4917 err => {
4918 if (err) return callback(err);
4919
4920 let exports;
4921 try {
4922 const {
4923 strictModuleErrorHandling,
4924 strictModuleExceptionHandling
4925 } = this.outputOptions;
4926 const __webpack_require__ = id => {
4927 const cached = moduleCache[id];
4928 if (cached !== undefined) {
4929 if (cached.error) throw cached.error;
4930 return cached.exports;
4931 }
4932 const moduleArgument = moduleArgumentsById.get(id);
4933 return __webpack_require_module__(moduleArgument, id);
4934 };
4935 const interceptModuleExecution = (__webpack_require__[
4936 RuntimeGlobals.interceptModuleExecution.replace(
4937 "__webpack_require__.",
4938 ""
4939 )
4940 ] = []);
4941 const moduleCache = (__webpack_require__[
4942 RuntimeGlobals.moduleCache.replace(
4943 "__webpack_require__.",
4944 ""
4945 )
4946 ] = {});
4947
4948 context.__webpack_require__ = __webpack_require__;
4949
4950 /**
4951 * @param {ExecuteModuleArgument} moduleArgument the module argument
4952 * @param {string=} id id
4953 * @returns {any} exports
4954 */
4955 const __webpack_require_module__ = (moduleArgument, id) => {
4956 var execOptions = {
4957 id,
4958 module: {
4959 id,
4960 exports: {},
4961 loaded: false,
4962 error: undefined
4963 },
4964 require: __webpack_require__
4965 };
4966 interceptModuleExecution.forEach(handler =>
4967 handler(execOptions)
4968 );
4969 const module = moduleArgument.module;
4970 this.buildTimeExecutedModules.add(module);
4971 const moduleObject = execOptions.module;
4972 moduleArgument.moduleObject = moduleObject;
4973 try {
4974 if (id) moduleCache[id] = moduleObject;
4975
4976 tryRunOrWebpackError(
4977 () =>
4978 this.hooks.executeModule.call(
4979 moduleArgument,
4980 context
4981 ),
4982 "Compilation.hooks.executeModule"
4983 );
4984 moduleObject.loaded = true;
4985 return moduleObject.exports;
4986 } catch (e) {
4987 if (strictModuleExceptionHandling) {
4988 if (id) delete moduleCache[id];
4989 } else if (strictModuleErrorHandling) {
4990 moduleObject.error = e;
4991 }
4992 if (!e.module) e.module = module;
4993 throw e;
4994 }
4995 };
4996
4997 for (const runtimeModule of chunkGraph.getChunkRuntimeModulesInOrder(
4998 chunk
4999 )) {
5000 __webpack_require_module__(
5001 moduleArgumentsMap.get(runtimeModule)
5002 );
5003 }
5004 exports = __webpack_require__(module.identifier());
5005 } catch (e) {
5006 const err = new WebpackError(
5007 `Execution of module code from module graph (${module.readableIdentifier(
5008 this.requestShortener
5009 )}) failed: ${e.message}`
5010 );
5011 err.stack = e.stack;
5012 err.module = e.module;
5013 return callback(err);
5014 }
5015
5016 callback(null, {
5017 exports,
5018 assets,
5019 cacheable,
5020 fileDependencies,
5021 contextDependencies,
5022 missingDependencies,
5023 buildDependencies
5024 });
5025 }
5026 );
5027 });
5028 });
5029 }
5030 );
5031 }
5032
5033 checkConstraints() {
5034 const chunkGraph = this.chunkGraph;
5035
5036 /** @type {Set<number|string>} */
5037 const usedIds = new Set();
5038
5039 for (const module of this.modules) {
5040 if (module.type === "runtime") continue;
5041 const moduleId = chunkGraph.getModuleId(module);
5042 if (moduleId === null) continue;
5043 if (usedIds.has(moduleId)) {
5044 throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
5045 }
5046 usedIds.add(moduleId);
5047 }
5048
5049 for (const chunk of this.chunks) {
5050 for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
5051 if (!this.modules.has(module)) {
5052 throw new Error(
5053 "checkConstraints: module in chunk but not in compilation " +
5054 ` ${chunk.debugId} ${module.debugId}`
5055 );
5056 }
5057 }
5058 for (const module of chunkGraph.getChunkEntryModulesIterable(chunk)) {
5059 if (!this.modules.has(module)) {
5060 throw new Error(
5061 "checkConstraints: entry module in chunk but not in compilation " +
5062 ` ${chunk.debugId} ${module.debugId}`
5063 );
5064 }
5065 }
5066 }
5067
5068 for (const chunkGroup of this.chunkGroups) {
5069 chunkGroup.checkConstraints();
5070 }
5071 }
5072}
5073
5074/**
5075 * @typedef {Object} FactorizeModuleOptions
5076 * @property {ModuleProfile} currentProfile
5077 * @property {ModuleFactory} factory
5078 * @property {Dependency[]} dependencies
5079 * @property {boolean=} factoryResult return full ModuleFactoryResult instead of only module
5080 * @property {Module | null} originModule
5081 * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
5082 * @property {string=} context
5083 */
5084
5085/**
5086 * @param {FactorizeModuleOptions} options options object
5087 * @param {ModuleCallback | ModuleFactoryResultCallback} callback callback
5088 * @returns {void}
5089 */
5090
5091// Workaround for typescript as it doesn't support function overloading in jsdoc within a class
5092Compilation.prototype.factorizeModule = /** @type {{
5093 (options: FactorizeModuleOptions & { factoryResult?: false }, callback: ModuleCallback): void;
5094 (options: FactorizeModuleOptions & { factoryResult: true }, callback: ModuleFactoryResultCallback): void;
5095}} */ (
5096 function (options, callback) {
5097 this.factorizeQueue.add(options, callback);
5098 }
5099);
5100
5101// Hide from typescript
5102const compilationPrototype = Compilation.prototype;
5103
5104// TODO webpack 6 remove
5105Object.defineProperty(compilationPrototype, "modifyHash", {
5106 writable: false,
5107 enumerable: false,
5108 configurable: false,
5109 value: () => {
5110 throw new Error(
5111 "Compilation.modifyHash was removed in favor of Compilation.hooks.fullHash"
5112 );
5113 }
5114});
5115
5116// TODO webpack 6 remove
5117Object.defineProperty(compilationPrototype, "cache", {
5118 enumerable: false,
5119 configurable: false,
5120 get: util.deprecate(
5121 /**
5122 * @this {Compilation} the compilation
5123 * @returns {Cache} the cache
5124 */
5125 function () {
5126 return this.compiler.cache;
5127 },
5128 "Compilation.cache was removed in favor of Compilation.getCache()",
5129 "DEP_WEBPACK_COMPILATION_CACHE"
5130 ),
5131 set: util.deprecate(
5132 v => {},
5133 "Compilation.cache was removed in favor of Compilation.getCache()",
5134 "DEP_WEBPACK_COMPILATION_CACHE"
5135 )
5136});
5137
5138/**
5139 * Add additional assets to the compilation.
5140 */
5141Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL = -2000;
5142
5143/**
5144 * Basic preprocessing of assets.
5145 */
5146Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS = -1000;
5147
5148/**
5149 * Derive new assets from existing assets.
5150 * Existing assets should not be treated as complete.
5151 */
5152Compilation.PROCESS_ASSETS_STAGE_DERIVED = -200;
5153
5154/**
5155 * Add additional sections to existing assets, like a banner or initialization code.
5156 */
5157Compilation.PROCESS_ASSETS_STAGE_ADDITIONS = -100;
5158
5159/**
5160 * Optimize existing assets in a general way.
5161 */
5162Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE = 100;
5163
5164/**
5165 * Optimize the count of existing assets, e. g. by merging them.
5166 * Only assets of the same type should be merged.
5167 * For assets of different types see PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE.
5168 */
5169Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT = 200;
5170
5171/**
5172 * Optimize the compatibility of existing assets, e. g. add polyfills or vendor-prefixes.
5173 */
5174Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY = 300;
5175
5176/**
5177 * Optimize the size of existing assets, e. g. by minimizing or omitting whitespace.
5178 */
5179Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE = 400;
5180
5181/**
5182 * Add development tooling to assets, e. g. by extracting a SourceMap.
5183 */
5184Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING = 500;
5185
5186/**
5187 * Optimize the count of existing assets, e. g. by inlining assets of into other assets.
5188 * Only assets of different types should be inlined.
5189 * For assets of the same type see PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT.
5190 */
5191Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE = 700;
5192
5193/**
5194 * Summarize the list of existing assets
5195 * e. g. creating an assets manifest of Service Workers.
5196 */
5197Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE = 1000;
5198
5199/**
5200 * Optimize the hashes of the assets, e. g. by generating real hashes of the asset content.
5201 */
5202Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH = 2500;
5203
5204/**
5205 * Optimize the transfer of existing assets, e. g. by preparing a compressed (gzip) file as separate asset.
5206 */
5207Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER = 3000;
5208
5209/**
5210 * Analyse existing assets.
5211 */
5212Compilation.PROCESS_ASSETS_STAGE_ANALYSE = 4000;
5213
5214/**
5215 * Creating assets for reporting purposes.
5216 */
5217Compilation.PROCESS_ASSETS_STAGE_REPORT = 5000;
5218
5219module.exports = Compilation;
5220
\No newline at end of file