UNPKG

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