source: frontend/node_modules/webpack/lib/Compilation.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

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