source: imaps-frontend/node_modules/webpack/lib/ChunkGraph.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

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