UNPKG

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