UNPKG

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