source: trip-planner-front/node_modules/webpack/lib/Compilation.js@ fa375fe

Last change on this file since fa375fe was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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