UNPKG

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