UNPKG

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