UNPKG

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