source: imaps-frontend/node_modules/webpack/lib/Compilation.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

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