UNPKG

53.2 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const util = require("util");
9const Entrypoint = require("./Entrypoint");
10const ModuleGraphConnection = require("./ModuleGraphConnection");
11const { first } = require("./util/SetHelpers");
12const SortableSet = require("./util/SortableSet");
13const {
14 compareModulesById,
15 compareIterables,
16 compareModulesByIdentifier,
17 concatComparators,
18 compareSelect,
19 compareIds
20} = require("./util/comparators");
21const createHash = require("./util/createHash");
22const findGraphRoots = require("./util/findGraphRoots");
23const {
24 RuntimeSpecMap,
25 RuntimeSpecSet,
26 runtimeToString,
27 mergeRuntime,
28 forEachRuntime
29} = require("./util/runtime");
30
31/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
32/** @typedef {import("./Chunk")} Chunk */
33/** @typedef {import("./ChunkGroup")} ChunkGroup */
34/** @typedef {import("./Module")} Module */
35/** @typedef {import("./ModuleGraph")} ModuleGraph */
36/** @typedef {import("./RuntimeModule")} RuntimeModule */
37/** @typedef {typeof import("./util/Hash")} Hash */
38/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
39
40/** @type {ReadonlySet<string>} */
41const EMPTY_SET = new Set();
42
43const ZERO_BIG_INT = BigInt(0);
44
45const compareModuleIterables = compareIterables(compareModulesByIdentifier);
46
47/** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */
48/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
49/** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
50
51/**
52 * @typedef {Object} ChunkSizeOptions
53 * @property {number=} chunkOverhead constant overhead for a chunk
54 * @property {number=} entryChunkMultiplicator multiplicator for initial chunks
55 */
56
57class ModuleHashInfo {
58 constructor(hash, renderedHash) {
59 this.hash = hash;
60 this.renderedHash = renderedHash;
61 }
62}
63
64/** @template T @typedef {(set: SortableSet<T>) => T[]} SetToArrayFunction<T> */
65
66/**
67 * @template T
68 * @param {SortableSet<T>} set the set
69 * @returns {T[]} set as array
70 */
71const getArray = set => {
72 return Array.from(set);
73};
74
75/**
76 * @param {SortableSet<Chunk>} chunks the chunks
77 * @returns {RuntimeSpecSet} runtimes
78 */
79const getModuleRuntimes = chunks => {
80 const runtimes = new RuntimeSpecSet();
81 for (const chunk of chunks) {
82 runtimes.add(chunk.runtime);
83 }
84 return runtimes;
85};
86
87/**
88 * @param {WeakMap<Module, Set<string>> | undefined} sourceTypesByModule sourceTypesByModule
89 * @returns {function (SortableSet<Module>): Map<string, SortableSet<Module>>} modules by source type
90 */
91const modulesBySourceType = sourceTypesByModule => set => {
92 /** @type {Map<string, SortableSet<Module>>} */
93 const map = new Map();
94 for (const module of set) {
95 const sourceTypes =
96 (sourceTypesByModule && sourceTypesByModule.get(module)) ||
97 module.getSourceTypes();
98 for (const sourceType of sourceTypes) {
99 let innerSet = map.get(sourceType);
100 if (innerSet === undefined) {
101 innerSet = new SortableSet();
102 map.set(sourceType, innerSet);
103 }
104 innerSet.add(module);
105 }
106 }
107 for (const [key, innerSet] of map) {
108 // When all modules have the source type, we reuse the original SortableSet
109 // to benefit from the shared cache (especially for sorting)
110 if (innerSet.size === set.size) {
111 map.set(key, set);
112 }
113 }
114 return map;
115};
116const defaultModulesBySourceType = modulesBySourceType(undefined);
117
118/** @type {WeakMap<Function, any>} */
119const createOrderedArrayFunctionMap = new WeakMap();
120
121/**
122 * @template T
123 * @param {function(T, T): -1|0|1} comparator comparator function
124 * @returns {SetToArrayFunction<T>} set as ordered array
125 */
126const createOrderedArrayFunction = comparator => {
127 /** @type {SetToArrayFunction<T>} */
128 let fn = createOrderedArrayFunctionMap.get(comparator);
129 if (fn !== undefined) return fn;
130 fn = set => {
131 set.sortWith(comparator);
132 return Array.from(set);
133 };
134 createOrderedArrayFunctionMap.set(comparator, fn);
135 return fn;
136};
137
138/**
139 * @param {Iterable<Module>} modules the modules to get the count/size of
140 * @returns {number} the size of the modules
141 */
142const getModulesSize = modules => {
143 let size = 0;
144 for (const module of modules) {
145 for (const type of module.getSourceTypes()) {
146 size += module.size(type);
147 }
148 }
149 return size;
150};
151
152/**
153 * @param {Iterable<Module>} modules the sortable Set to get the size of
154 * @returns {Record<string, number>} the sizes of the modules
155 */
156const getModulesSizes = modules => {
157 let sizes = Object.create(null);
158 for (const module of modules) {
159 for (const type of module.getSourceTypes()) {
160 sizes[type] = (sizes[type] || 0) + module.size(type);
161 }
162 }
163 return sizes;
164};
165
166/**
167 * @param {Chunk} a chunk
168 * @param {Chunk} b chunk
169 * @returns {boolean} true, if a is always a parent of b
170 */
171const isAvailableChunk = (a, b) => {
172 const queue = new Set(b.groupsIterable);
173 for (const chunkGroup of queue) {
174 if (a.isInGroup(chunkGroup)) continue;
175 if (chunkGroup.isInitial()) return false;
176 for (const parent of chunkGroup.parentsIterable) {
177 queue.add(parent);
178 }
179 }
180 return true;
181};
182
183class ChunkGraphModule {
184 constructor() {
185 /** @type {SortableSet<Chunk>} */
186 this.chunks = new SortableSet();
187 /** @type {Set<Chunk> | undefined} */
188 this.entryInChunks = undefined;
189 /** @type {Set<Chunk> | undefined} */
190 this.runtimeInChunks = undefined;
191 /** @type {RuntimeSpecMap<ModuleHashInfo>} */
192 this.hashes = undefined;
193 /** @type {string | number} */
194 this.id = null;
195 /** @type {RuntimeSpecMap<Set<string>> | undefined} */
196 this.runtimeRequirements = undefined;
197 /** @type {RuntimeSpecMap<string>} */
198 this.graphHashes = undefined;
199 /** @type {RuntimeSpecMap<string>} */
200 this.graphHashesWithConnections = undefined;
201 }
202}
203
204class ChunkGraphChunk {
205 constructor() {
206 /** @type {SortableSet<Module>} */
207 this.modules = new SortableSet();
208 /** @type {WeakMap<Module, Set<string>> | undefined} */
209 this.sourceTypesByModule = undefined;
210 /** @type {Map<Module, Entrypoint>} */
211 this.entryModules = new Map();
212 /** @type {SortableSet<RuntimeModule>} */
213 this.runtimeModules = new SortableSet();
214 /** @type {Set<RuntimeModule> | undefined} */
215 this.fullHashModules = undefined;
216 /** @type {Set<RuntimeModule> | undefined} */
217 this.dependentHashModules = undefined;
218 /** @type {Set<string> | undefined} */
219 this.runtimeRequirements = undefined;
220 /** @type {Set<string>} */
221 this.runtimeRequirementsInTree = new Set();
222
223 this._modulesBySourceType = defaultModulesBySourceType;
224 }
225}
226
227class ChunkGraph {
228 /**
229 * @param {ModuleGraph} moduleGraph the module graph
230 * @param {string | Hash} hashFunction the hash function to use
231 */
232 constructor(moduleGraph, hashFunction = "md4") {
233 /** @private @type {WeakMap<Module, ChunkGraphModule>} */
234 this._modules = new WeakMap();
235 /** @private @type {WeakMap<Chunk, ChunkGraphChunk>} */
236 this._chunks = new WeakMap();
237 /** @private @type {WeakMap<AsyncDependenciesBlock, ChunkGroup>} */
238 this._blockChunkGroups = new WeakMap();
239 /** @private @type {Map<string, string | number>} */
240 this._runtimeIds = new Map();
241 /** @type {ModuleGraph} */
242 this.moduleGraph = moduleGraph;
243
244 this._hashFunction = hashFunction;
245
246 this._getGraphRoots = this._getGraphRoots.bind(this);
247 }
248
249 /**
250 * @private
251 * @param {Module} module the module
252 * @returns {ChunkGraphModule} internal module
253 */
254 _getChunkGraphModule(module) {
255 let cgm = this._modules.get(module);
256 if (cgm === undefined) {
257 cgm = new ChunkGraphModule();
258 this._modules.set(module, cgm);
259 }
260 return cgm;
261 }
262
263 /**
264 * @private
265 * @param {Chunk} chunk the chunk
266 * @returns {ChunkGraphChunk} internal chunk
267 */
268 _getChunkGraphChunk(chunk) {
269 let cgc = this._chunks.get(chunk);
270 if (cgc === undefined) {
271 cgc = new ChunkGraphChunk();
272 this._chunks.set(chunk, cgc);
273 }
274 return cgc;
275 }
276
277 /**
278 * @param {SortableSet<Module>} set the sortable Set to get the roots of
279 * @returns {Module[]} the graph roots
280 */
281 _getGraphRoots(set) {
282 const { moduleGraph } = this;
283 return Array.from(
284 findGraphRoots(set, module => {
285 /** @type {Set<Module>} */
286 const set = new Set();
287 const addDependencies = module => {
288 for (const connection of moduleGraph.getOutgoingConnections(module)) {
289 if (!connection.module) continue;
290 const activeState = connection.getActiveState(undefined);
291 if (activeState === false) continue;
292 if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) {
293 addDependencies(connection.module);
294 continue;
295 }
296 set.add(connection.module);
297 }
298 };
299 addDependencies(module);
300 return set;
301 })
302 ).sort(compareModulesByIdentifier);
303 }
304
305 /**
306 * @param {Chunk} chunk the new chunk
307 * @param {Module} module the module
308 * @returns {void}
309 */
310 connectChunkAndModule(chunk, module) {
311 const cgm = this._getChunkGraphModule(module);
312 const cgc = this._getChunkGraphChunk(chunk);
313 cgm.chunks.add(chunk);
314 cgc.modules.add(module);
315 }
316
317 /**
318 * @param {Chunk} chunk the chunk
319 * @param {Module} module the module
320 * @returns {void}
321 */
322 disconnectChunkAndModule(chunk, module) {
323 const cgm = this._getChunkGraphModule(module);
324 const cgc = this._getChunkGraphChunk(chunk);
325 cgc.modules.delete(module);
326 // No need to invalidate cgc._modulesBySourceType because we modified cgc.modules anyway
327 if (cgc.sourceTypesByModule) cgc.sourceTypesByModule.delete(module);
328 cgm.chunks.delete(chunk);
329 }
330
331 /**
332 * @param {Chunk} chunk the chunk which will be disconnected
333 * @returns {void}
334 */
335 disconnectChunk(chunk) {
336 const cgc = this._getChunkGraphChunk(chunk);
337 for (const module of cgc.modules) {
338 const cgm = this._getChunkGraphModule(module);
339 cgm.chunks.delete(chunk);
340 }
341 cgc.modules.clear();
342 chunk.disconnectFromGroups();
343 ChunkGraph.clearChunkGraphForChunk(chunk);
344 }
345
346 /**
347 * @param {Chunk} chunk the chunk
348 * @param {Iterable<Module>} modules the modules
349 * @returns {void}
350 */
351 attachModules(chunk, modules) {
352 const cgc = this._getChunkGraphChunk(chunk);
353 for (const module of modules) {
354 cgc.modules.add(module);
355 }
356 }
357
358 /**
359 * @param {Chunk} chunk the chunk
360 * @param {Iterable<RuntimeModule>} modules the runtime modules
361 * @returns {void}
362 */
363 attachRuntimeModules(chunk, modules) {
364 const cgc = this._getChunkGraphChunk(chunk);
365 for (const module of modules) {
366 cgc.runtimeModules.add(module);
367 }
368 }
369
370 /**
371 * @param {Chunk} chunk the chunk
372 * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
373 * @returns {void}
374 */
375 attachFullHashModules(chunk, modules) {
376 const cgc = this._getChunkGraphChunk(chunk);
377 if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
378 for (const module of modules) {
379 cgc.fullHashModules.add(module);
380 }
381 }
382
383 /**
384 * @param {Chunk} chunk the chunk
385 * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
386 * @returns {void}
387 */
388 attachDependentHashModules(chunk, modules) {
389 const cgc = this._getChunkGraphChunk(chunk);
390 if (cgc.dependentHashModules === undefined)
391 cgc.dependentHashModules = new Set();
392 for (const module of modules) {
393 cgc.dependentHashModules.add(module);
394 }
395 }
396
397 /**
398 * @param {Module} oldModule the replaced module
399 * @param {Module} newModule the replacing module
400 * @returns {void}
401 */
402 replaceModule(oldModule, newModule) {
403 const oldCgm = this._getChunkGraphModule(oldModule);
404 const newCgm = this._getChunkGraphModule(newModule);
405
406 for (const chunk of oldCgm.chunks) {
407 const cgc = this._getChunkGraphChunk(chunk);
408 cgc.modules.delete(oldModule);
409 cgc.modules.add(newModule);
410 newCgm.chunks.add(chunk);
411 }
412 oldCgm.chunks.clear();
413
414 if (oldCgm.entryInChunks !== undefined) {
415 if (newCgm.entryInChunks === undefined) {
416 newCgm.entryInChunks = new Set();
417 }
418 for (const chunk of oldCgm.entryInChunks) {
419 const cgc = this._getChunkGraphChunk(chunk);
420 const old = cgc.entryModules.get(oldModule);
421 /** @type {Map<Module, Entrypoint>} */
422 const newEntryModules = new Map();
423 for (const [m, cg] of cgc.entryModules) {
424 if (m === oldModule) {
425 newEntryModules.set(newModule, old);
426 } else {
427 newEntryModules.set(m, cg);
428 }
429 }
430 cgc.entryModules = newEntryModules;
431 newCgm.entryInChunks.add(chunk);
432 }
433 oldCgm.entryInChunks = undefined;
434 }
435
436 if (oldCgm.runtimeInChunks !== undefined) {
437 if (newCgm.runtimeInChunks === undefined) {
438 newCgm.runtimeInChunks = new Set();
439 }
440 for (const chunk of oldCgm.runtimeInChunks) {
441 const cgc = this._getChunkGraphChunk(chunk);
442 cgc.runtimeModules.delete(/** @type {RuntimeModule} */ (oldModule));
443 cgc.runtimeModules.add(/** @type {RuntimeModule} */ (newModule));
444 newCgm.runtimeInChunks.add(chunk);
445 if (
446 cgc.fullHashModules !== undefined &&
447 cgc.fullHashModules.has(/** @type {RuntimeModule} */ (oldModule))
448 ) {
449 cgc.fullHashModules.delete(/** @type {RuntimeModule} */ (oldModule));
450 cgc.fullHashModules.add(/** @type {RuntimeModule} */ (newModule));
451 }
452 if (
453 cgc.dependentHashModules !== undefined &&
454 cgc.dependentHashModules.has(/** @type {RuntimeModule} */ (oldModule))
455 ) {
456 cgc.dependentHashModules.delete(
457 /** @type {RuntimeModule} */ (oldModule)
458 );
459 cgc.dependentHashModules.add(
460 /** @type {RuntimeModule} */ (newModule)
461 );
462 }
463 }
464 oldCgm.runtimeInChunks = undefined;
465 }
466 }
467
468 /**
469 * @param {Module} module the checked module
470 * @param {Chunk} chunk the checked chunk
471 * @returns {boolean} true, if the chunk contains the module
472 */
473 isModuleInChunk(module, chunk) {
474 const cgc = this._getChunkGraphChunk(chunk);
475 return cgc.modules.has(module);
476 }
477
478 /**
479 * @param {Module} module the checked module
480 * @param {ChunkGroup} chunkGroup the checked chunk group
481 * @returns {boolean} true, if the chunk contains the module
482 */
483 isModuleInChunkGroup(module, chunkGroup) {
484 for (const chunk of chunkGroup.chunks) {
485 if (this.isModuleInChunk(module, chunk)) return true;
486 }
487 return false;
488 }
489
490 /**
491 * @param {Module} module the checked module
492 * @returns {boolean} true, if the module is entry of any chunk
493 */
494 isEntryModule(module) {
495 const cgm = this._getChunkGraphModule(module);
496 return cgm.entryInChunks !== undefined;
497 }
498
499 /**
500 * @param {Module} module the module
501 * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
502 */
503 getModuleChunksIterable(module) {
504 const cgm = this._getChunkGraphModule(module);
505 return cgm.chunks;
506 }
507
508 /**
509 * @param {Module} module the module
510 * @param {function(Chunk, Chunk): -1|0|1} sortFn sort function
511 * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
512 */
513 getOrderedModuleChunksIterable(module, sortFn) {
514 const cgm = this._getChunkGraphModule(module);
515 cgm.chunks.sortWith(sortFn);
516 return cgm.chunks;
517 }
518
519 /**
520 * @param {Module} module the module
521 * @returns {Chunk[]} array of chunks (cached, do not modify)
522 */
523 getModuleChunks(module) {
524 const cgm = this._getChunkGraphModule(module);
525 return cgm.chunks.getFromCache(getArray);
526 }
527
528 /**
529 * @param {Module} module the module
530 * @returns {number} the number of chunk which contain the module
531 */
532 getNumberOfModuleChunks(module) {
533 const cgm = this._getChunkGraphModule(module);
534 return cgm.chunks.size;
535 }
536
537 /**
538 * @param {Module} module the module
539 * @returns {RuntimeSpecSet} runtimes
540 */
541 getModuleRuntimes(module) {
542 const cgm = this._getChunkGraphModule(module);
543 return cgm.chunks.getFromUnorderedCache(getModuleRuntimes);
544 }
545
546 /**
547 * @param {Chunk} chunk the chunk
548 * @returns {number} the number of modules which are contained in this chunk
549 */
550 getNumberOfChunkModules(chunk) {
551 const cgc = this._getChunkGraphChunk(chunk);
552 return cgc.modules.size;
553 }
554
555 /**
556 * @param {Chunk} chunk the chunk
557 * @returns {number} the number of full hash modules which are contained in this chunk
558 */
559 getNumberOfChunkFullHashModules(chunk) {
560 const cgc = this._getChunkGraphChunk(chunk);
561 return cgc.fullHashModules === undefined ? 0 : cgc.fullHashModules.size;
562 }
563
564 /**
565 * @param {Chunk} chunk the chunk
566 * @returns {Iterable<Module>} return the modules for this chunk
567 */
568 getChunkModulesIterable(chunk) {
569 const cgc = this._getChunkGraphChunk(chunk);
570 return cgc.modules;
571 }
572
573 /**
574 * @param {Chunk} chunk the chunk
575 * @param {string} sourceType source type
576 * @returns {Iterable<Module> | undefined} return the modules for this chunk
577 */
578 getChunkModulesIterableBySourceType(chunk, sourceType) {
579 const cgc = this._getChunkGraphChunk(chunk);
580 const modulesWithSourceType = cgc.modules
581 .getFromUnorderedCache(cgc._modulesBySourceType)
582 .get(sourceType);
583 return modulesWithSourceType;
584 }
585
586 /**
587 * @param {Chunk} chunk chunk
588 * @param {Module} module chunk module
589 * @param {Set<string>} sourceTypes source types
590 */
591 setChunkModuleSourceTypes(chunk, module, sourceTypes) {
592 const cgc = this._getChunkGraphChunk(chunk);
593 if (cgc.sourceTypesByModule === undefined) {
594 cgc.sourceTypesByModule = new WeakMap();
595 }
596 cgc.sourceTypesByModule.set(module, sourceTypes);
597 // Update cgc._modulesBySourceType to invalidate the cache
598 cgc._modulesBySourceType = modulesBySourceType(cgc.sourceTypesByModule);
599 }
600
601 /**
602 * @param {Chunk} chunk chunk
603 * @param {Module} module chunk module
604 * @returns {Set<string>} source types
605 */
606 getChunkModuleSourceTypes(chunk, module) {
607 const cgc = this._getChunkGraphChunk(chunk);
608 if (cgc.sourceTypesByModule === undefined) {
609 return module.getSourceTypes();
610 }
611 return cgc.sourceTypesByModule.get(module) || module.getSourceTypes();
612 }
613
614 /**
615 * @param {Module} module module
616 * @returns {Set<string>} source types
617 */
618 getModuleSourceTypes(module) {
619 return (
620 this._getOverwrittenModuleSourceTypes(module) || module.getSourceTypes()
621 );
622 }
623
624 /**
625 * @param {Module} module module
626 * @returns {Set<string> | undefined} source types
627 */
628 _getOverwrittenModuleSourceTypes(module) {
629 let newSet = false;
630 let sourceTypes;
631 for (const chunk of this.getModuleChunksIterable(module)) {
632 const cgc = this._getChunkGraphChunk(chunk);
633 if (cgc.sourceTypesByModule === undefined) return;
634 const st = cgc.sourceTypesByModule.get(module);
635 if (st === undefined) return;
636 if (!sourceTypes) {
637 sourceTypes = st;
638 continue;
639 } else if (!newSet) {
640 for (const type of st) {
641 if (!newSet) {
642 if (!sourceTypes.has(type)) {
643 newSet = true;
644 sourceTypes = new Set(sourceTypes);
645 sourceTypes.add(type);
646 }
647 } else {
648 sourceTypes.add(type);
649 }
650 }
651 } else {
652 for (const type of st) sourceTypes.add(type);
653 }
654 }
655
656 return sourceTypes;
657 }
658
659 /**
660 * @param {Chunk} chunk the chunk
661 * @param {function(Module, Module): -1|0|1} comparator comparator function
662 * @returns {Iterable<Module>} return the modules for this chunk
663 */
664 getOrderedChunkModulesIterable(chunk, comparator) {
665 const cgc = this._getChunkGraphChunk(chunk);
666 cgc.modules.sortWith(comparator);
667 return cgc.modules;
668 }
669
670 /**
671 * @param {Chunk} chunk the chunk
672 * @param {string} sourceType source type
673 * @param {function(Module, Module): -1|0|1} comparator comparator function
674 * @returns {Iterable<Module> | undefined} return the modules for this chunk
675 */
676 getOrderedChunkModulesIterableBySourceType(chunk, sourceType, comparator) {
677 const cgc = this._getChunkGraphChunk(chunk);
678 const modulesWithSourceType = cgc.modules
679 .getFromUnorderedCache(cgc._modulesBySourceType)
680 .get(sourceType);
681 if (modulesWithSourceType === undefined) return undefined;
682 modulesWithSourceType.sortWith(comparator);
683 return modulesWithSourceType;
684 }
685
686 /**
687 * @param {Chunk} chunk the chunk
688 * @returns {Module[]} return the modules for this chunk (cached, do not modify)
689 */
690 getChunkModules(chunk) {
691 const cgc = this._getChunkGraphChunk(chunk);
692 return cgc.modules.getFromUnorderedCache(getArray);
693 }
694
695 /**
696 * @param {Chunk} chunk the chunk
697 * @param {function(Module, Module): -1|0|1} comparator comparator function
698 * @returns {Module[]} return the modules for this chunk (cached, do not modify)
699 */
700 getOrderedChunkModules(chunk, comparator) {
701 const cgc = this._getChunkGraphChunk(chunk);
702 const arrayFunction = createOrderedArrayFunction(comparator);
703 return cgc.modules.getFromUnorderedCache(arrayFunction);
704 }
705
706 /**
707 * @param {Chunk} chunk the chunk
708 * @param {ModuleFilterPredicate} filterFn function used to filter modules
709 * @param {boolean} includeAllChunks all chunks or only async chunks
710 * @returns {Record<string|number, (string|number)[]>} chunk to module ids object
711 */
712 getChunkModuleIdMap(chunk, filterFn, includeAllChunks = false) {
713 /** @type {Record<string|number, (string|number)[]>} */
714 const chunkModuleIdMap = Object.create(null);
715
716 for (const asyncChunk of includeAllChunks
717 ? chunk.getAllReferencedChunks()
718 : chunk.getAllAsyncChunks()) {
719 /** @type {(string|number)[]} */
720 let array;
721 for (const module of this.getOrderedChunkModulesIterable(
722 asyncChunk,
723 compareModulesById(this)
724 )) {
725 if (filterFn(module)) {
726 if (array === undefined) {
727 array = [];
728 chunkModuleIdMap[asyncChunk.id] = array;
729 }
730 const moduleId = this.getModuleId(module);
731 array.push(moduleId);
732 }
733 }
734 }
735
736 return chunkModuleIdMap;
737 }
738
739 /**
740 * @param {Chunk} chunk the chunk
741 * @param {ModuleFilterPredicate} filterFn function used to filter modules
742 * @param {number} hashLength length of the hash
743 * @param {boolean} includeAllChunks all chunks or only async chunks
744 * @returns {Record<string|number, Record<string|number, string>>} chunk to module id to module hash object
745 */
746 getChunkModuleRenderedHashMap(
747 chunk,
748 filterFn,
749 hashLength = 0,
750 includeAllChunks = false
751 ) {
752 /** @type {Record<string|number, Record<string|number, string>>} */
753 const chunkModuleHashMap = Object.create(null);
754
755 for (const asyncChunk of includeAllChunks
756 ? chunk.getAllReferencedChunks()
757 : chunk.getAllAsyncChunks()) {
758 /** @type {Record<string|number, string>} */
759 let idToHashMap;
760 for (const module of this.getOrderedChunkModulesIterable(
761 asyncChunk,
762 compareModulesById(this)
763 )) {
764 if (filterFn(module)) {
765 if (idToHashMap === undefined) {
766 idToHashMap = Object.create(null);
767 chunkModuleHashMap[asyncChunk.id] = idToHashMap;
768 }
769 const moduleId = this.getModuleId(module);
770 const hash = this.getRenderedModuleHash(module, asyncChunk.runtime);
771 idToHashMap[moduleId] = hashLength ? hash.slice(0, hashLength) : hash;
772 }
773 }
774 }
775
776 return chunkModuleHashMap;
777 }
778
779 /**
780 * @param {Chunk} chunk the chunk
781 * @param {ChunkFilterPredicate} filterFn function used to filter chunks
782 * @returns {Record<string|number, boolean>} chunk map
783 */
784 getChunkConditionMap(chunk, filterFn) {
785 const map = Object.create(null);
786 for (const c of chunk.getAllReferencedChunks()) {
787 map[c.id] = filterFn(c, this);
788 }
789 return map;
790 }
791
792 /**
793 * @param {Chunk} chunk the chunk
794 * @param {ModuleFilterPredicate} filterFn predicate function used to filter modules
795 * @param {ChunkFilterPredicate=} filterChunkFn predicate function used to filter chunks
796 * @returns {boolean} return true if module exists in graph
797 */
798 hasModuleInGraph(chunk, filterFn, filterChunkFn) {
799 const queue = new Set(chunk.groupsIterable);
800 const chunksProcessed = new Set();
801
802 for (const chunkGroup of queue) {
803 for (const innerChunk of chunkGroup.chunks) {
804 if (!chunksProcessed.has(innerChunk)) {
805 chunksProcessed.add(innerChunk);
806 if (!filterChunkFn || filterChunkFn(innerChunk, this)) {
807 for (const module of this.getChunkModulesIterable(innerChunk)) {
808 if (filterFn(module)) {
809 return true;
810 }
811 }
812 }
813 }
814 }
815 for (const child of chunkGroup.childrenIterable) {
816 queue.add(child);
817 }
818 }
819 return false;
820 }
821
822 /**
823 * @param {Chunk} chunkA first chunk
824 * @param {Chunk} chunkB second chunk
825 * @returns {-1|0|1} this is a comparator function like sort and returns -1, 0, or 1 based on sort order
826 */
827 compareChunks(chunkA, chunkB) {
828 const cgcA = this._getChunkGraphChunk(chunkA);
829 const cgcB = this._getChunkGraphChunk(chunkB);
830 if (cgcA.modules.size > cgcB.modules.size) return -1;
831 if (cgcA.modules.size < cgcB.modules.size) return 1;
832 cgcA.modules.sortWith(compareModulesByIdentifier);
833 cgcB.modules.sortWith(compareModulesByIdentifier);
834 return compareModuleIterables(cgcA.modules, cgcB.modules);
835 }
836
837 /**
838 * @param {Chunk} chunk the chunk
839 * @returns {number} total size of all modules in the chunk
840 */
841 getChunkModulesSize(chunk) {
842 const cgc = this._getChunkGraphChunk(chunk);
843 return cgc.modules.getFromUnorderedCache(getModulesSize);
844 }
845
846 /**
847 * @param {Chunk} chunk the chunk
848 * @returns {Record<string, number>} total sizes of all modules in the chunk by source type
849 */
850 getChunkModulesSizes(chunk) {
851 const cgc = this._getChunkGraphChunk(chunk);
852 return cgc.modules.getFromUnorderedCache(getModulesSizes);
853 }
854
855 /**
856 * @param {Chunk} chunk the chunk
857 * @returns {Module[]} root modules of the chunks (ordered by identifier)
858 */
859 getChunkRootModules(chunk) {
860 const cgc = this._getChunkGraphChunk(chunk);
861 return cgc.modules.getFromUnorderedCache(this._getGraphRoots);
862 }
863
864 /**
865 * @param {Chunk} chunk the chunk
866 * @param {ChunkSizeOptions} options options object
867 * @returns {number} total size of the chunk
868 */
869 getChunkSize(chunk, options = {}) {
870 const cgc = this._getChunkGraphChunk(chunk);
871 const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize);
872 const chunkOverhead =
873 typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
874 const entryChunkMultiplicator =
875 typeof options.entryChunkMultiplicator === "number"
876 ? options.entryChunkMultiplicator
877 : 10;
878 return (
879 chunkOverhead +
880 modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1)
881 );
882 }
883
884 /**
885 * @param {Chunk} chunkA chunk
886 * @param {Chunk} chunkB chunk
887 * @param {ChunkSizeOptions} options options object
888 * @returns {number} total size of the chunk or false if chunks can't be integrated
889 */
890 getIntegratedChunksSize(chunkA, chunkB, options = {}) {
891 const cgcA = this._getChunkGraphChunk(chunkA);
892 const cgcB = this._getChunkGraphChunk(chunkB);
893 const allModules = new Set(cgcA.modules);
894 for (const m of cgcB.modules) allModules.add(m);
895 let modulesSize = getModulesSize(allModules);
896 const chunkOverhead =
897 typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
898 const entryChunkMultiplicator =
899 typeof options.entryChunkMultiplicator === "number"
900 ? options.entryChunkMultiplicator
901 : 10;
902 return (
903 chunkOverhead +
904 modulesSize *
905 (chunkA.canBeInitial() || chunkB.canBeInitial()
906 ? entryChunkMultiplicator
907 : 1)
908 );
909 }
910
911 /**
912 * @param {Chunk} chunkA chunk
913 * @param {Chunk} chunkB chunk
914 * @returns {boolean} true, if chunks could be integrated
915 */
916 canChunksBeIntegrated(chunkA, chunkB) {
917 if (chunkA.preventIntegration || chunkB.preventIntegration) {
918 return false;
919 }
920
921 const hasRuntimeA = chunkA.hasRuntime();
922 const hasRuntimeB = chunkB.hasRuntime();
923
924 if (hasRuntimeA !== hasRuntimeB) {
925 if (hasRuntimeA) {
926 return isAvailableChunk(chunkA, chunkB);
927 } else if (hasRuntimeB) {
928 return isAvailableChunk(chunkB, chunkA);
929 } else {
930 return false;
931 }
932 }
933
934 if (
935 this.getNumberOfEntryModules(chunkA) > 0 ||
936 this.getNumberOfEntryModules(chunkB) > 0
937 ) {
938 return false;
939 }
940
941 return true;
942 }
943
944 /**
945 * @param {Chunk} chunkA the target chunk
946 * @param {Chunk} chunkB the chunk to integrate
947 * @returns {void}
948 */
949 integrateChunks(chunkA, chunkB) {
950 // Decide for one name (deterministic)
951 if (chunkA.name && chunkB.name) {
952 if (
953 this.getNumberOfEntryModules(chunkA) > 0 ===
954 this.getNumberOfEntryModules(chunkB) > 0
955 ) {
956 // When both chunks have entry modules or none have one, use
957 // shortest name
958 if (chunkA.name.length !== chunkB.name.length) {
959 chunkA.name =
960 chunkA.name.length < chunkB.name.length ? chunkA.name : chunkB.name;
961 } else {
962 chunkA.name = chunkA.name < chunkB.name ? chunkA.name : chunkB.name;
963 }
964 } else if (this.getNumberOfEntryModules(chunkB) > 0) {
965 // Pick the name of the chunk with the entry module
966 chunkA.name = chunkB.name;
967 }
968 } else if (chunkB.name) {
969 chunkA.name = chunkB.name;
970 }
971
972 // Merge id name hints
973 for (const hint of chunkB.idNameHints) {
974 chunkA.idNameHints.add(hint);
975 }
976
977 // Merge runtime
978 chunkA.runtime = mergeRuntime(chunkA.runtime, chunkB.runtime);
979
980 // getChunkModules is used here to create a clone, because disconnectChunkAndModule modifies
981 for (const module of this.getChunkModules(chunkB)) {
982 this.disconnectChunkAndModule(chunkB, module);
983 this.connectChunkAndModule(chunkA, module);
984 }
985
986 for (const [module, chunkGroup] of Array.from(
987 this.getChunkEntryModulesWithChunkGroupIterable(chunkB)
988 )) {
989 this.disconnectChunkAndEntryModule(chunkB, module);
990 this.connectChunkAndEntryModule(chunkA, module, chunkGroup);
991 }
992
993 for (const chunkGroup of chunkB.groupsIterable) {
994 chunkGroup.replaceChunk(chunkB, chunkA);
995 chunkA.addGroup(chunkGroup);
996 chunkB.removeGroup(chunkGroup);
997 }
998 ChunkGraph.clearChunkGraphForChunk(chunkB);
999 }
1000
1001 /**
1002 * @param {Chunk} chunk the chunk to upgrade
1003 * @returns {void}
1004 */
1005 upgradeDependentToFullHashModules(chunk) {
1006 const cgc = this._getChunkGraphChunk(chunk);
1007 if (cgc.dependentHashModules === undefined) return;
1008 if (cgc.fullHashModules === undefined) {
1009 cgc.fullHashModules = cgc.dependentHashModules;
1010 } else {
1011 for (const m of cgc.dependentHashModules) {
1012 cgc.fullHashModules.add(m);
1013 }
1014 cgc.dependentHashModules = undefined;
1015 }
1016 }
1017
1018 /**
1019 * @param {Module} module the checked module
1020 * @param {Chunk} chunk the checked chunk
1021 * @returns {boolean} true, if the chunk contains the module as entry
1022 */
1023 isEntryModuleInChunk(module, chunk) {
1024 const cgc = this._getChunkGraphChunk(chunk);
1025 return cgc.entryModules.has(module);
1026 }
1027
1028 /**
1029 * @param {Chunk} chunk the new chunk
1030 * @param {Module} module the entry module
1031 * @param {Entrypoint=} entrypoint the chunk group which must be loaded before the module is executed
1032 * @returns {void}
1033 */
1034 connectChunkAndEntryModule(chunk, module, entrypoint) {
1035 const cgm = this._getChunkGraphModule(module);
1036 const cgc = this._getChunkGraphChunk(chunk);
1037 if (cgm.entryInChunks === undefined) {
1038 cgm.entryInChunks = new Set();
1039 }
1040 cgm.entryInChunks.add(chunk);
1041 cgc.entryModules.set(module, entrypoint);
1042 }
1043
1044 /**
1045 * @param {Chunk} chunk the new chunk
1046 * @param {RuntimeModule} module the runtime module
1047 * @returns {void}
1048 */
1049 connectChunkAndRuntimeModule(chunk, module) {
1050 const cgm = this._getChunkGraphModule(module);
1051 const cgc = this._getChunkGraphChunk(chunk);
1052 if (cgm.runtimeInChunks === undefined) {
1053 cgm.runtimeInChunks = new Set();
1054 }
1055 cgm.runtimeInChunks.add(chunk);
1056 cgc.runtimeModules.add(module);
1057 }
1058
1059 /**
1060 * @param {Chunk} chunk the new chunk
1061 * @param {RuntimeModule} module the module that require a full hash
1062 * @returns {void}
1063 */
1064 addFullHashModuleToChunk(chunk, module) {
1065 const cgc = this._getChunkGraphChunk(chunk);
1066 if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
1067 cgc.fullHashModules.add(module);
1068 }
1069
1070 /**
1071 * @param {Chunk} chunk the new chunk
1072 * @param {RuntimeModule} module the module that require a full hash
1073 * @returns {void}
1074 */
1075 addDependentHashModuleToChunk(chunk, module) {
1076 const cgc = this._getChunkGraphChunk(chunk);
1077 if (cgc.dependentHashModules === undefined)
1078 cgc.dependentHashModules = new Set();
1079 cgc.dependentHashModules.add(module);
1080 }
1081
1082 /**
1083 * @param {Chunk} chunk the new chunk
1084 * @param {Module} module the entry module
1085 * @returns {void}
1086 */
1087 disconnectChunkAndEntryModule(chunk, module) {
1088 const cgm = this._getChunkGraphModule(module);
1089 const cgc = this._getChunkGraphChunk(chunk);
1090 cgm.entryInChunks.delete(chunk);
1091 if (cgm.entryInChunks.size === 0) {
1092 cgm.entryInChunks = undefined;
1093 }
1094 cgc.entryModules.delete(module);
1095 }
1096
1097 /**
1098 * @param {Chunk} chunk the new chunk
1099 * @param {RuntimeModule} module the runtime module
1100 * @returns {void}
1101 */
1102 disconnectChunkAndRuntimeModule(chunk, module) {
1103 const cgm = this._getChunkGraphModule(module);
1104 const cgc = this._getChunkGraphChunk(chunk);
1105 cgm.runtimeInChunks.delete(chunk);
1106 if (cgm.runtimeInChunks.size === 0) {
1107 cgm.runtimeInChunks = undefined;
1108 }
1109 cgc.runtimeModules.delete(module);
1110 }
1111
1112 /**
1113 * @param {Module} module the entry module, it will no longer be entry
1114 * @returns {void}
1115 */
1116 disconnectEntryModule(module) {
1117 const cgm = this._getChunkGraphModule(module);
1118 for (const chunk of cgm.entryInChunks) {
1119 const cgc = this._getChunkGraphChunk(chunk);
1120 cgc.entryModules.delete(module);
1121 }
1122 cgm.entryInChunks = undefined;
1123 }
1124
1125 /**
1126 * @param {Chunk} chunk the chunk, for which all entries will be removed
1127 * @returns {void}
1128 */
1129 disconnectEntries(chunk) {
1130 const cgc = this._getChunkGraphChunk(chunk);
1131 for (const module of cgc.entryModules.keys()) {
1132 const cgm = this._getChunkGraphModule(module);
1133 cgm.entryInChunks.delete(chunk);
1134 if (cgm.entryInChunks.size === 0) {
1135 cgm.entryInChunks = undefined;
1136 }
1137 }
1138 cgc.entryModules.clear();
1139 }
1140
1141 /**
1142 * @param {Chunk} chunk the chunk
1143 * @returns {number} the amount of entry modules in chunk
1144 */
1145 getNumberOfEntryModules(chunk) {
1146 const cgc = this._getChunkGraphChunk(chunk);
1147 return cgc.entryModules.size;
1148 }
1149
1150 /**
1151 * @param {Chunk} chunk the chunk
1152 * @returns {number} the amount of entry modules in chunk
1153 */
1154 getNumberOfRuntimeModules(chunk) {
1155 const cgc = this._getChunkGraphChunk(chunk);
1156 return cgc.runtimeModules.size;
1157 }
1158
1159 /**
1160 * @param {Chunk} chunk the chunk
1161 * @returns {Iterable<Module>} iterable of modules (do not modify)
1162 */
1163 getChunkEntryModulesIterable(chunk) {
1164 const cgc = this._getChunkGraphChunk(chunk);
1165 return cgc.entryModules.keys();
1166 }
1167
1168 /**
1169 * @param {Chunk} chunk the chunk
1170 * @returns {Iterable<Chunk>} iterable of chunks
1171 */
1172 getChunkEntryDependentChunksIterable(chunk) {
1173 /** @type {Set<Chunk>} */
1174 const set = new Set();
1175 for (const chunkGroup of chunk.groupsIterable) {
1176 if (chunkGroup instanceof Entrypoint) {
1177 const entrypointChunk = chunkGroup.getEntrypointChunk();
1178 const cgc = this._getChunkGraphChunk(entrypointChunk);
1179 for (const chunkGroup of cgc.entryModules.values()) {
1180 for (const c of chunkGroup.chunks) {
1181 if (c !== chunk && c !== entrypointChunk && !c.hasRuntime()) {
1182 set.add(c);
1183 }
1184 }
1185 }
1186 }
1187 }
1188
1189 return set;
1190 }
1191
1192 /**
1193 * @param {Chunk} chunk the chunk
1194 * @returns {boolean} true, when it has dependent chunks
1195 */
1196 hasChunkEntryDependentChunks(chunk) {
1197 const cgc = this._getChunkGraphChunk(chunk);
1198 for (const chunkGroup of cgc.entryModules.values()) {
1199 for (const c of chunkGroup.chunks) {
1200 if (c !== chunk) {
1201 return true;
1202 }
1203 }
1204 }
1205 return false;
1206 }
1207
1208 /**
1209 * @param {Chunk} chunk the chunk
1210 * @returns {Iterable<RuntimeModule>} iterable of modules (do not modify)
1211 */
1212 getChunkRuntimeModulesIterable(chunk) {
1213 const cgc = this._getChunkGraphChunk(chunk);
1214 return cgc.runtimeModules;
1215 }
1216
1217 /**
1218 * @param {Chunk} chunk the chunk
1219 * @returns {RuntimeModule[]} array of modules in order of execution
1220 */
1221 getChunkRuntimeModulesInOrder(chunk) {
1222 const cgc = this._getChunkGraphChunk(chunk);
1223 const array = Array.from(cgc.runtimeModules);
1224 array.sort(
1225 concatComparators(
1226 compareSelect(
1227 /**
1228 * @param {RuntimeModule} r runtime module
1229 * @returns {number=} stage
1230 */
1231 r => r.stage,
1232 compareIds
1233 ),
1234 compareModulesByIdentifier
1235 )
1236 );
1237 return array;
1238 }
1239
1240 /**
1241 * @param {Chunk} chunk the chunk
1242 * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
1243 */
1244 getChunkFullHashModulesIterable(chunk) {
1245 const cgc = this._getChunkGraphChunk(chunk);
1246 return cgc.fullHashModules;
1247 }
1248
1249 /**
1250 * @param {Chunk} chunk the chunk
1251 * @returns {ReadonlySet<RuntimeModule> | undefined} set of modules (do not modify)
1252 */
1253 getChunkFullHashModulesSet(chunk) {
1254 const cgc = this._getChunkGraphChunk(chunk);
1255 return cgc.fullHashModules;
1256 }
1257
1258 /**
1259 * @param {Chunk} chunk the chunk
1260 * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
1261 */
1262 getChunkDependentHashModulesIterable(chunk) {
1263 const cgc = this._getChunkGraphChunk(chunk);
1264 return cgc.dependentHashModules;
1265 }
1266
1267 /**
1268 * @param {Chunk} chunk the chunk
1269 * @returns {Iterable<EntryModuleWithChunkGroup>} iterable of modules (do not modify)
1270 */
1271 getChunkEntryModulesWithChunkGroupIterable(chunk) {
1272 const cgc = this._getChunkGraphChunk(chunk);
1273 return cgc.entryModules;
1274 }
1275
1276 /**
1277 * @param {AsyncDependenciesBlock} depBlock the async block
1278 * @returns {ChunkGroup} the chunk group
1279 */
1280 getBlockChunkGroup(depBlock) {
1281 return this._blockChunkGroups.get(depBlock);
1282 }
1283
1284 /**
1285 * @param {AsyncDependenciesBlock} depBlock the async block
1286 * @param {ChunkGroup} chunkGroup the chunk group
1287 * @returns {void}
1288 */
1289 connectBlockAndChunkGroup(depBlock, chunkGroup) {
1290 this._blockChunkGroups.set(depBlock, chunkGroup);
1291 chunkGroup.addBlock(depBlock);
1292 }
1293
1294 /**
1295 * @param {ChunkGroup} chunkGroup the chunk group
1296 * @returns {void}
1297 */
1298 disconnectChunkGroup(chunkGroup) {
1299 for (const block of chunkGroup.blocksIterable) {
1300 this._blockChunkGroups.delete(block);
1301 }
1302 // TODO refactor by moving blocks list into ChunkGraph
1303 chunkGroup._blocks.clear();
1304 }
1305
1306 /**
1307 * @param {Module} module the module
1308 * @returns {string | number} the id of the module
1309 */
1310 getModuleId(module) {
1311 const cgm = this._getChunkGraphModule(module);
1312 return cgm.id;
1313 }
1314
1315 /**
1316 * @param {Module} module the module
1317 * @param {string | number} id the id of the module
1318 * @returns {void}
1319 */
1320 setModuleId(module, id) {
1321 const cgm = this._getChunkGraphModule(module);
1322 cgm.id = id;
1323 }
1324
1325 /**
1326 * @param {string} runtime runtime
1327 * @returns {string | number} the id of the runtime
1328 */
1329 getRuntimeId(runtime) {
1330 return this._runtimeIds.get(runtime);
1331 }
1332
1333 /**
1334 * @param {string} runtime runtime
1335 * @param {string | number} id the id of the runtime
1336 * @returns {void}
1337 */
1338 setRuntimeId(runtime, id) {
1339 this._runtimeIds.set(runtime, id);
1340 }
1341
1342 /**
1343 * @template T
1344 * @param {Module} module the module
1345 * @param {RuntimeSpecMap<T>} hashes hashes data
1346 * @param {RuntimeSpec} runtime the runtime
1347 * @returns {T} hash
1348 */
1349 _getModuleHashInfo(module, hashes, runtime) {
1350 if (!hashes) {
1351 throw new Error(
1352 `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
1353 runtime
1354 )} (hashes not set at all)`
1355 );
1356 } else if (runtime === undefined) {
1357 const hashInfoItems = new Set(hashes.values());
1358 if (hashInfoItems.size !== 1) {
1359 throw new Error(
1360 `No unique hash info entry for unspecified runtime for ${module.identifier()} (existing runtimes: ${Array.from(
1361 hashes.keys(),
1362 r => runtimeToString(r)
1363 ).join(", ")}).
1364Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
1365 );
1366 }
1367 return first(hashInfoItems);
1368 } else {
1369 const hashInfo = hashes.get(runtime);
1370 if (!hashInfo) {
1371 throw new Error(
1372 `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
1373 runtime
1374 )} (available runtimes ${Array.from(
1375 hashes.keys(),
1376 runtimeToString
1377 ).join(", ")})`
1378 );
1379 }
1380 return hashInfo;
1381 }
1382 }
1383
1384 /**
1385 * @param {Module} module the module
1386 * @param {RuntimeSpec} runtime the runtime
1387 * @returns {boolean} true, if the module has hashes for this runtime
1388 */
1389 hasModuleHashes(module, runtime) {
1390 const cgm = this._getChunkGraphModule(module);
1391 const hashes = cgm.hashes;
1392 return hashes && hashes.has(runtime);
1393 }
1394
1395 /**
1396 * @param {Module} module the module
1397 * @param {RuntimeSpec} runtime the runtime
1398 * @returns {string} hash
1399 */
1400 getModuleHash(module, runtime) {
1401 const cgm = this._getChunkGraphModule(module);
1402 const hashes = cgm.hashes;
1403 return this._getModuleHashInfo(module, hashes, runtime).hash;
1404 }
1405
1406 /**
1407 * @param {Module} module the module
1408 * @param {RuntimeSpec} runtime the runtime
1409 * @returns {string} hash
1410 */
1411 getRenderedModuleHash(module, runtime) {
1412 const cgm = this._getChunkGraphModule(module);
1413 const hashes = cgm.hashes;
1414 return this._getModuleHashInfo(module, hashes, runtime).renderedHash;
1415 }
1416
1417 /**
1418 * @param {Module} module the module
1419 * @param {RuntimeSpec} runtime the runtime
1420 * @param {string} hash the full hash
1421 * @param {string} renderedHash the shortened hash for rendering
1422 * @returns {void}
1423 */
1424 setModuleHashes(module, runtime, hash, renderedHash) {
1425 const cgm = this._getChunkGraphModule(module);
1426 if (cgm.hashes === undefined) {
1427 cgm.hashes = new RuntimeSpecMap();
1428 }
1429 cgm.hashes.set(runtime, new ModuleHashInfo(hash, renderedHash));
1430 }
1431
1432 /**
1433 * @param {Module} module the module
1434 * @param {RuntimeSpec} runtime the runtime
1435 * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph when transferOwnership not false)
1436 * @param {boolean} transferOwnership true: transfer ownership of the items object, false: items is immutable and shared and won't be modified
1437 * @returns {void}
1438 */
1439 addModuleRuntimeRequirements(
1440 module,
1441 runtime,
1442 items,
1443 transferOwnership = true
1444 ) {
1445 const cgm = this._getChunkGraphModule(module);
1446 const runtimeRequirementsMap = cgm.runtimeRequirements;
1447 if (runtimeRequirementsMap === undefined) {
1448 const map = new RuntimeSpecMap();
1449 // TODO avoid cloning item and track ownership instead
1450 map.set(runtime, transferOwnership ? items : new Set(items));
1451 cgm.runtimeRequirements = map;
1452 return;
1453 }
1454 runtimeRequirementsMap.update(runtime, runtimeRequirements => {
1455 if (runtimeRequirements === undefined) {
1456 return transferOwnership ? items : new Set(items);
1457 } else if (!transferOwnership || runtimeRequirements.size >= items.size) {
1458 for (const item of items) runtimeRequirements.add(item);
1459 return runtimeRequirements;
1460 } else {
1461 for (const item of runtimeRequirements) items.add(item);
1462 return items;
1463 }
1464 });
1465 }
1466
1467 /**
1468 * @param {Chunk} chunk the chunk
1469 * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph)
1470 * @returns {void}
1471 */
1472 addChunkRuntimeRequirements(chunk, items) {
1473 const cgc = this._getChunkGraphChunk(chunk);
1474 const runtimeRequirements = cgc.runtimeRequirements;
1475 if (runtimeRequirements === undefined) {
1476 cgc.runtimeRequirements = items;
1477 } else if (runtimeRequirements.size >= items.size) {
1478 for (const item of items) runtimeRequirements.add(item);
1479 } else {
1480 for (const item of runtimeRequirements) items.add(item);
1481 cgc.runtimeRequirements = items;
1482 }
1483 }
1484
1485 /**
1486 * @param {Chunk} chunk the chunk
1487 * @param {Iterable<string>} items runtime requirements to be added
1488 * @returns {void}
1489 */
1490 addTreeRuntimeRequirements(chunk, items) {
1491 const cgc = this._getChunkGraphChunk(chunk);
1492 const runtimeRequirements = cgc.runtimeRequirementsInTree;
1493 for (const item of items) runtimeRequirements.add(item);
1494 }
1495
1496 /**
1497 * @param {Module} module the module
1498 * @param {RuntimeSpec} runtime the runtime
1499 * @returns {ReadonlySet<string>} runtime requirements
1500 */
1501 getModuleRuntimeRequirements(module, runtime) {
1502 const cgm = this._getChunkGraphModule(module);
1503 const runtimeRequirements =
1504 cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime);
1505 return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
1506 }
1507
1508 /**
1509 * @param {Chunk} chunk the chunk
1510 * @returns {ReadonlySet<string>} runtime requirements
1511 */
1512 getChunkRuntimeRequirements(chunk) {
1513 const cgc = this._getChunkGraphChunk(chunk);
1514 const runtimeRequirements = cgc.runtimeRequirements;
1515 return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
1516 }
1517
1518 /**
1519 * @param {Module} module the module
1520 * @param {RuntimeSpec} runtime the runtime
1521 * @param {boolean} withConnections include connections
1522 * @returns {string} hash
1523 */
1524 getModuleGraphHash(module, runtime, withConnections = true) {
1525 const cgm = this._getChunkGraphModule(module);
1526 return withConnections
1527 ? this._getModuleGraphHashWithConnections(cgm, module, runtime)
1528 : this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16);
1529 }
1530
1531 /**
1532 * @param {Module} module the module
1533 * @param {RuntimeSpec} runtime the runtime
1534 * @param {boolean} withConnections include connections
1535 * @returns {bigint} hash
1536 */
1537 getModuleGraphHashBigInt(module, runtime, withConnections = true) {
1538 const cgm = this._getChunkGraphModule(module);
1539 return withConnections
1540 ? BigInt(
1541 `0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}`
1542 )
1543 : this._getModuleGraphHashBigInt(cgm, module, runtime);
1544 }
1545
1546 /**
1547 * @param {ChunkGraphModule} cgm the ChunkGraphModule
1548 * @param {Module} module the module
1549 * @param {RuntimeSpec} runtime the runtime
1550 * @returns {bigint} hash as big int
1551 */
1552 _getModuleGraphHashBigInt(cgm, module, runtime) {
1553 if (cgm.graphHashes === undefined) {
1554 cgm.graphHashes = new RuntimeSpecMap();
1555 }
1556 const graphHash = cgm.graphHashes.provide(runtime, () => {
1557 const hash = createHash(this._hashFunction);
1558 hash.update(`${cgm.id}${this.moduleGraph.isAsync(module)}`);
1559 const sourceTypes = this._getOverwrittenModuleSourceTypes(module);
1560 if (sourceTypes !== undefined) {
1561 for (const type of sourceTypes) hash.update(type);
1562 }
1563 this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime);
1564 return BigInt(`0x${/** @type {string} */ (hash.digest("hex"))}`);
1565 });
1566 return graphHash;
1567 }
1568
1569 /**
1570 * @param {ChunkGraphModule} cgm the ChunkGraphModule
1571 * @param {Module} module the module
1572 * @param {RuntimeSpec} runtime the runtime
1573 * @returns {string} hash
1574 */
1575 _getModuleGraphHashWithConnections(cgm, module, runtime) {
1576 if (cgm.graphHashesWithConnections === undefined) {
1577 cgm.graphHashesWithConnections = new RuntimeSpecMap();
1578 }
1579 const activeStateToString = state => {
1580 if (state === false) return "F";
1581 if (state === true) return "T";
1582 if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O";
1583 throw new Error("Not implemented active state");
1584 };
1585 const strict = module.buildMeta && module.buildMeta.strictHarmonyModule;
1586 return cgm.graphHashesWithConnections.provide(runtime, () => {
1587 const graphHash = this._getModuleGraphHashBigInt(
1588 cgm,
1589 module,
1590 runtime
1591 ).toString(16);
1592 const connections = this.moduleGraph.getOutgoingConnections(module);
1593 /** @type {Set<Module>} */
1594 const activeNamespaceModules = new Set();
1595 /** @type {Map<string, Module | Set<Module>>} */
1596 const connectedModules = new Map();
1597 const processConnection = (connection, stateInfo) => {
1598 const module = connection.module;
1599 stateInfo += module.getExportsType(this.moduleGraph, strict);
1600 // cspell:word Tnamespace
1601 if (stateInfo === "Tnamespace") activeNamespaceModules.add(module);
1602 else {
1603 const oldModule = connectedModules.get(stateInfo);
1604 if (oldModule === undefined) {
1605 connectedModules.set(stateInfo, module);
1606 } else if (oldModule instanceof Set) {
1607 oldModule.add(module);
1608 } else if (oldModule !== module) {
1609 connectedModules.set(stateInfo, new Set([oldModule, module]));
1610 }
1611 }
1612 };
1613 if (runtime === undefined || typeof runtime === "string") {
1614 for (const connection of connections) {
1615 const state = connection.getActiveState(runtime);
1616 if (state === false) continue;
1617 processConnection(connection, state === true ? "T" : "O");
1618 }
1619 } else {
1620 // cspell:word Tnamespace
1621 for (const connection of connections) {
1622 const states = new Set();
1623 let stateInfo = "";
1624 forEachRuntime(
1625 runtime,
1626 runtime => {
1627 const state = connection.getActiveState(runtime);
1628 states.add(state);
1629 stateInfo += activeStateToString(state) + runtime;
1630 },
1631 true
1632 );
1633 if (states.size === 1) {
1634 const state = first(states);
1635 if (state === false) continue;
1636 stateInfo = activeStateToString(state);
1637 }
1638 processConnection(connection, stateInfo);
1639 }
1640 }
1641 // cspell:word Tnamespace
1642 if (activeNamespaceModules.size === 0 && connectedModules.size === 0)
1643 return graphHash;
1644 const connectedModulesInOrder =
1645 connectedModules.size > 1
1646 ? Array.from(connectedModules).sort(([a], [b]) => (a < b ? -1 : 1))
1647 : connectedModules;
1648 const hash = createHash(this._hashFunction);
1649 const addModuleToHash = module => {
1650 hash.update(
1651 this._getModuleGraphHashBigInt(
1652 this._getChunkGraphModule(module),
1653 module,
1654 runtime
1655 ).toString(16)
1656 );
1657 };
1658 const addModulesToHash = modules => {
1659 let xor = ZERO_BIG_INT;
1660 for (const m of modules) {
1661 xor =
1662 xor ^
1663 this._getModuleGraphHashBigInt(
1664 this._getChunkGraphModule(m),
1665 m,
1666 runtime
1667 );
1668 }
1669 hash.update(xor.toString(16));
1670 };
1671 if (activeNamespaceModules.size === 1)
1672 addModuleToHash(activeNamespaceModules.values().next().value);
1673 else if (activeNamespaceModules.size > 1)
1674 addModulesToHash(activeNamespaceModules);
1675 for (const [stateInfo, modules] of connectedModulesInOrder) {
1676 hash.update(stateInfo);
1677 if (modules instanceof Set) {
1678 addModulesToHash(modules);
1679 } else {
1680 addModuleToHash(modules);
1681 }
1682 }
1683 hash.update(graphHash);
1684 return /** @type {string} */ (hash.digest("hex"));
1685 });
1686 }
1687
1688 /**
1689 * @param {Chunk} chunk the chunk
1690 * @returns {ReadonlySet<string>} runtime requirements
1691 */
1692 getTreeRuntimeRequirements(chunk) {
1693 const cgc = this._getChunkGraphChunk(chunk);
1694 return cgc.runtimeRequirementsInTree;
1695 }
1696
1697 // TODO remove in webpack 6
1698 /**
1699 * @param {Module} module the module
1700 * @param {string} deprecateMessage message for the deprecation message
1701 * @param {string} deprecationCode code for the deprecation
1702 * @returns {ChunkGraph} the chunk graph
1703 */
1704 static getChunkGraphForModule(module, deprecateMessage, deprecationCode) {
1705 const fn = deprecateGetChunkGraphForModuleMap.get(deprecateMessage);
1706 if (fn) return fn(module);
1707 const newFn = util.deprecate(
1708 /**
1709 * @param {Module} module the module
1710 * @returns {ChunkGraph} the chunk graph
1711 */
1712 module => {
1713 const chunkGraph = chunkGraphForModuleMap.get(module);
1714 if (!chunkGraph)
1715 throw new Error(
1716 deprecateMessage +
1717 ": There was no ChunkGraph assigned to the Module for backward-compat (Use the new API)"
1718 );
1719 return chunkGraph;
1720 },
1721 deprecateMessage + ": Use new ChunkGraph API",
1722 deprecationCode
1723 );
1724 deprecateGetChunkGraphForModuleMap.set(deprecateMessage, newFn);
1725 return newFn(module);
1726 }
1727
1728 // TODO remove in webpack 6
1729 /**
1730 * @param {Module} module the module
1731 * @param {ChunkGraph} chunkGraph the chunk graph
1732 * @returns {void}
1733 */
1734 static setChunkGraphForModule(module, chunkGraph) {
1735 chunkGraphForModuleMap.set(module, chunkGraph);
1736 }
1737
1738 // TODO remove in webpack 6
1739 /**
1740 * @param {Module} module the module
1741 * @returns {void}
1742 */
1743 static clearChunkGraphForModule(module) {
1744 chunkGraphForModuleMap.delete(module);
1745 }
1746
1747 // TODO remove in webpack 6
1748 /**
1749 * @param {Chunk} chunk the chunk
1750 * @param {string} deprecateMessage message for the deprecation message
1751 * @param {string} deprecationCode code for the deprecation
1752 * @returns {ChunkGraph} the chunk graph
1753 */
1754 static getChunkGraphForChunk(chunk, deprecateMessage, deprecationCode) {
1755 const fn = deprecateGetChunkGraphForChunkMap.get(deprecateMessage);
1756 if (fn) return fn(chunk);
1757 const newFn = util.deprecate(
1758 /**
1759 * @param {Chunk} chunk the chunk
1760 * @returns {ChunkGraph} the chunk graph
1761 */
1762 chunk => {
1763 const chunkGraph = chunkGraphForChunkMap.get(chunk);
1764 if (!chunkGraph)
1765 throw new Error(
1766 deprecateMessage +
1767 "There was no ChunkGraph assigned to the Chunk for backward-compat (Use the new API)"
1768 );
1769 return chunkGraph;
1770 },
1771 deprecateMessage + ": Use new ChunkGraph API",
1772 deprecationCode
1773 );
1774 deprecateGetChunkGraphForChunkMap.set(deprecateMessage, newFn);
1775 return newFn(chunk);
1776 }
1777
1778 // TODO remove in webpack 6
1779 /**
1780 * @param {Chunk} chunk the chunk
1781 * @param {ChunkGraph} chunkGraph the chunk graph
1782 * @returns {void}
1783 */
1784 static setChunkGraphForChunk(chunk, chunkGraph) {
1785 chunkGraphForChunkMap.set(chunk, chunkGraph);
1786 }
1787
1788 // TODO remove in webpack 6
1789 /**
1790 * @param {Chunk} chunk the chunk
1791 * @returns {void}
1792 */
1793 static clearChunkGraphForChunk(chunk) {
1794 chunkGraphForChunkMap.delete(chunk);
1795 }
1796}
1797
1798// TODO remove in webpack 6
1799/** @type {WeakMap<Module, ChunkGraph>} */
1800const chunkGraphForModuleMap = new WeakMap();
1801
1802// TODO remove in webpack 6
1803/** @type {WeakMap<Chunk, ChunkGraph>} */
1804const chunkGraphForChunkMap = new WeakMap();
1805
1806// TODO remove in webpack 6
1807/** @type {Map<string, (module: Module) => ChunkGraph>} */
1808const deprecateGetChunkGraphForModuleMap = new Map();
1809
1810// TODO remove in webpack 6
1811/** @type {Map<string, (chunk: Chunk) => ChunkGraph>} */
1812const deprecateGetChunkGraphForChunkMap = new Map();
1813
1814module.exports = ChunkGraph;