UNPKG

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