UNPKG

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