UNPKG

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