diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
| commit | d5f14083061f2ce6a42313188443a42e30796320 (patch) | |
| tree | cc6a9889e08b29595a76a33b9e7b4ef84866468b /node_modules/webpack/lib/ChunkGraph.js | |
| parent | b1a6ea021f29f182b62f9f81024a3d8ac8621b7f (diff) | |
added make browserlist(autoprefixer) work fixed
Diffstat (limited to 'node_modules/webpack/lib/ChunkGraph.js')
| -rw-r--r-- | node_modules/webpack/lib/ChunkGraph.js | 1814 |
1 files changed, 1814 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/ChunkGraph.js b/node_modules/webpack/lib/ChunkGraph.js new file mode 100644 index 00000000..a1914351 --- /dev/null +++ b/node_modules/webpack/lib/ChunkGraph.js @@ -0,0 +1,1814 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const util = require("util"); +const Entrypoint = require("./Entrypoint"); +const ModuleGraphConnection = require("./ModuleGraphConnection"); +const { first } = require("./util/SetHelpers"); +const SortableSet = require("./util/SortableSet"); +const { + compareModulesById, + compareIterables, + compareModulesByIdentifier, + concatComparators, + compareSelect, + compareIds +} = require("./util/comparators"); +const createHash = require("./util/createHash"); +const findGraphRoots = require("./util/findGraphRoots"); +const { + RuntimeSpecMap, + RuntimeSpecSet, + runtimeToString, + mergeRuntime, + forEachRuntime +} = require("./util/runtime"); + +/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./ModuleGraph")} ModuleGraph */ +/** @typedef {import("./RuntimeModule")} RuntimeModule */ +/** @typedef {typeof import("./util/Hash")} Hash */ +/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */ + +/** @type {ReadonlySet<string>} */ +const EMPTY_SET = new Set(); + +const ZERO_BIG_INT = BigInt(0); + +const compareModuleIterables = compareIterables(compareModulesByIdentifier); + +/** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */ +/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */ +/** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */ + +/** + * @typedef {Object} ChunkSizeOptions + * @property {number=} chunkOverhead constant overhead for a chunk + * @property {number=} entryChunkMultiplicator multiplicator for initial chunks + */ + +class ModuleHashInfo { + constructor(hash, renderedHash) { + this.hash = hash; + this.renderedHash = renderedHash; + } +} + +/** @template T @typedef {(set: SortableSet<T>) => T[]} SetToArrayFunction<T> */ + +/** + * @template T + * @param {SortableSet<T>} set the set + * @returns {T[]} set as array + */ +const getArray = set => { + return Array.from(set); +}; + +/** + * @param {SortableSet<Chunk>} chunks the chunks + * @returns {RuntimeSpecSet} runtimes + */ +const getModuleRuntimes = chunks => { + const runtimes = new RuntimeSpecSet(); + for (const chunk of chunks) { + runtimes.add(chunk.runtime); + } + return runtimes; +}; + +/** + * @param {WeakMap<Module, Set<string>> | undefined} sourceTypesByModule sourceTypesByModule + * @returns {function (SortableSet<Module>): Map<string, SortableSet<Module>>} modules by source type + */ +const modulesBySourceType = sourceTypesByModule => set => { + /** @type {Map<string, SortableSet<Module>>} */ + const map = new Map(); + for (const module of set) { + const sourceTypes = + (sourceTypesByModule && sourceTypesByModule.get(module)) || + module.getSourceTypes(); + for (const sourceType of sourceTypes) { + let innerSet = map.get(sourceType); + if (innerSet === undefined) { + innerSet = new SortableSet(); + map.set(sourceType, innerSet); + } + innerSet.add(module); + } + } + for (const [key, innerSet] of map) { + // When all modules have the source type, we reuse the original SortableSet + // to benefit from the shared cache (especially for sorting) + if (innerSet.size === set.size) { + map.set(key, set); + } + } + return map; +}; +const defaultModulesBySourceType = modulesBySourceType(undefined); + +/** @type {WeakMap<Function, any>} */ +const createOrderedArrayFunctionMap = new WeakMap(); + +/** + * @template T + * @param {function(T, T): -1|0|1} comparator comparator function + * @returns {SetToArrayFunction<T>} set as ordered array + */ +const createOrderedArrayFunction = comparator => { + /** @type {SetToArrayFunction<T>} */ + let fn = createOrderedArrayFunctionMap.get(comparator); + if (fn !== undefined) return fn; + fn = set => { + set.sortWith(comparator); + return Array.from(set); + }; + createOrderedArrayFunctionMap.set(comparator, fn); + return fn; +}; + +/** + * @param {Iterable<Module>} modules the modules to get the count/size of + * @returns {number} the size of the modules + */ +const getModulesSize = modules => { + let size = 0; + for (const module of modules) { + for (const type of module.getSourceTypes()) { + size += module.size(type); + } + } + return size; +}; + +/** + * @param {Iterable<Module>} modules the sortable Set to get the size of + * @returns {Record<string, number>} the sizes of the modules + */ +const getModulesSizes = modules => { + let sizes = Object.create(null); + for (const module of modules) { + for (const type of module.getSourceTypes()) { + sizes[type] = (sizes[type] || 0) + module.size(type); + } + } + return sizes; +}; + +/** + * @param {Chunk} a chunk + * @param {Chunk} b chunk + * @returns {boolean} true, if a is always a parent of b + */ +const isAvailableChunk = (a, b) => { + const queue = new Set(b.groupsIterable); + for (const chunkGroup of queue) { + if (a.isInGroup(chunkGroup)) continue; + if (chunkGroup.isInitial()) return false; + for (const parent of chunkGroup.parentsIterable) { + queue.add(parent); + } + } + return true; +}; + +class ChunkGraphModule { + constructor() { + /** @type {SortableSet<Chunk>} */ + this.chunks = new SortableSet(); + /** @type {Set<Chunk> | undefined} */ + this.entryInChunks = undefined; + /** @type {Set<Chunk> | undefined} */ + this.runtimeInChunks = undefined; + /** @type {RuntimeSpecMap<ModuleHashInfo> | undefined} */ + this.hashes = undefined; + /** @type {string | number} */ + this.id = null; + /** @type {RuntimeSpecMap<Set<string>> | undefined} */ + this.runtimeRequirements = undefined; + /** @type {RuntimeSpecMap<string>} */ + this.graphHashes = undefined; + /** @type {RuntimeSpecMap<string>} */ + this.graphHashesWithConnections = undefined; + } +} + +class ChunkGraphChunk { + constructor() { + /** @type {SortableSet<Module>} */ + this.modules = new SortableSet(); + /** @type {WeakMap<Module, Set<string>> | undefined} */ + this.sourceTypesByModule = undefined; + /** @type {Map<Module, Entrypoint>} */ + this.entryModules = new Map(); + /** @type {SortableSet<RuntimeModule>} */ + this.runtimeModules = new SortableSet(); + /** @type {Set<RuntimeModule> | undefined} */ + this.fullHashModules = undefined; + /** @type {Set<RuntimeModule> | undefined} */ + this.dependentHashModules = undefined; + /** @type {Set<string> | undefined} */ + this.runtimeRequirements = undefined; + /** @type {Set<string>} */ + this.runtimeRequirementsInTree = new Set(); + + this._modulesBySourceType = defaultModulesBySourceType; + } +} + +class ChunkGraph { + /** + * @param {ModuleGraph} moduleGraph the module graph + * @param {string | Hash} hashFunction the hash function to use + */ + constructor(moduleGraph, hashFunction = "md4") { + /** @private @type {WeakMap<Module, ChunkGraphModule>} */ + this._modules = new WeakMap(); + /** @private @type {WeakMap<Chunk, ChunkGraphChunk>} */ + this._chunks = new WeakMap(); + /** @private @type {WeakMap<AsyncDependenciesBlock, ChunkGroup>} */ + this._blockChunkGroups = new WeakMap(); + /** @private @type {Map<string, string | number>} */ + this._runtimeIds = new Map(); + /** @type {ModuleGraph} */ + this.moduleGraph = moduleGraph; + + this._hashFunction = hashFunction; + + this._getGraphRoots = this._getGraphRoots.bind(this); + } + + /** + * @private + * @param {Module} module the module + * @returns {ChunkGraphModule} internal module + */ + _getChunkGraphModule(module) { + let cgm = this._modules.get(module); + if (cgm === undefined) { + cgm = new ChunkGraphModule(); + this._modules.set(module, cgm); + } + return cgm; + } + + /** + * @private + * @param {Chunk} chunk the chunk + * @returns {ChunkGraphChunk} internal chunk + */ + _getChunkGraphChunk(chunk) { + let cgc = this._chunks.get(chunk); + if (cgc === undefined) { + cgc = new ChunkGraphChunk(); + this._chunks.set(chunk, cgc); + } + return cgc; + } + + /** + * @param {SortableSet<Module>} set the sortable Set to get the roots of + * @returns {Module[]} the graph roots + */ + _getGraphRoots(set) { + const { moduleGraph } = this; + return Array.from( + findGraphRoots(set, module => { + /** @type {Set<Module>} */ + const set = new Set(); + const addDependencies = module => { + for (const connection of moduleGraph.getOutgoingConnections(module)) { + if (!connection.module) continue; + const activeState = connection.getActiveState(undefined); + if (activeState === false) continue; + if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) { + addDependencies(connection.module); + continue; + } + set.add(connection.module); + } + }; + addDependencies(module); + return set; + }) + ).sort(compareModulesByIdentifier); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {Module} module the module + * @returns {void} + */ + connectChunkAndModule(chunk, module) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + cgm.chunks.add(chunk); + cgc.modules.add(module); + } + + /** + * @param {Chunk} chunk the chunk + * @param {Module} module the module + * @returns {void} + */ + disconnectChunkAndModule(chunk, module) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + cgc.modules.delete(module); + // No need to invalidate cgc._modulesBySourceType because we modified cgc.modules anyway + if (cgc.sourceTypesByModule) cgc.sourceTypesByModule.delete(module); + cgm.chunks.delete(chunk); + } + + /** + * @param {Chunk} chunk the chunk which will be disconnected + * @returns {void} + */ + disconnectChunk(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + for (const module of cgc.modules) { + const cgm = this._getChunkGraphModule(module); + cgm.chunks.delete(chunk); + } + cgc.modules.clear(); + chunk.disconnectFromGroups(); + ChunkGraph.clearChunkGraphForChunk(chunk); + } + + /** + * @param {Chunk} chunk the chunk + * @param {Iterable<Module>} modules the modules + * @returns {void} + */ + attachModules(chunk, modules) { + const cgc = this._getChunkGraphChunk(chunk); + for (const module of modules) { + cgc.modules.add(module); + } + } + + /** + * @param {Chunk} chunk the chunk + * @param {Iterable<RuntimeModule>} modules the runtime modules + * @returns {void} + */ + attachRuntimeModules(chunk, modules) { + const cgc = this._getChunkGraphChunk(chunk); + for (const module of modules) { + cgc.runtimeModules.add(module); + } + } + + /** + * @param {Chunk} chunk the chunk + * @param {Iterable<RuntimeModule>} modules the modules that require a full hash + * @returns {void} + */ + attachFullHashModules(chunk, modules) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set(); + for (const module of modules) { + cgc.fullHashModules.add(module); + } + } + + /** + * @param {Chunk} chunk the chunk + * @param {Iterable<RuntimeModule>} modules the modules that require a full hash + * @returns {void} + */ + attachDependentHashModules(chunk, modules) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.dependentHashModules === undefined) + cgc.dependentHashModules = new Set(); + for (const module of modules) { + cgc.dependentHashModules.add(module); + } + } + + /** + * @param {Module} oldModule the replaced module + * @param {Module} newModule the replacing module + * @returns {void} + */ + replaceModule(oldModule, newModule) { + const oldCgm = this._getChunkGraphModule(oldModule); + const newCgm = this._getChunkGraphModule(newModule); + + for (const chunk of oldCgm.chunks) { + const cgc = this._getChunkGraphChunk(chunk); + cgc.modules.delete(oldModule); + cgc.modules.add(newModule); + newCgm.chunks.add(chunk); + } + oldCgm.chunks.clear(); + + if (oldCgm.entryInChunks !== undefined) { + if (newCgm.entryInChunks === undefined) { + newCgm.entryInChunks = new Set(); + } + for (const chunk of oldCgm.entryInChunks) { + const cgc = this._getChunkGraphChunk(chunk); + const old = cgc.entryModules.get(oldModule); + /** @type {Map<Module, Entrypoint>} */ + const newEntryModules = new Map(); + for (const [m, cg] of cgc.entryModules) { + if (m === oldModule) { + newEntryModules.set(newModule, old); + } else { + newEntryModules.set(m, cg); + } + } + cgc.entryModules = newEntryModules; + newCgm.entryInChunks.add(chunk); + } + oldCgm.entryInChunks = undefined; + } + + if (oldCgm.runtimeInChunks !== undefined) { + if (newCgm.runtimeInChunks === undefined) { + newCgm.runtimeInChunks = new Set(); + } + for (const chunk of oldCgm.runtimeInChunks) { + const cgc = this._getChunkGraphChunk(chunk); + cgc.runtimeModules.delete(/** @type {RuntimeModule} */ (oldModule)); + cgc.runtimeModules.add(/** @type {RuntimeModule} */ (newModule)); + newCgm.runtimeInChunks.add(chunk); + if ( + cgc.fullHashModules !== undefined && + cgc.fullHashModules.has(/** @type {RuntimeModule} */ (oldModule)) + ) { + cgc.fullHashModules.delete(/** @type {RuntimeModule} */ (oldModule)); + cgc.fullHashModules.add(/** @type {RuntimeModule} */ (newModule)); + } + if ( + cgc.dependentHashModules !== undefined && + cgc.dependentHashModules.has(/** @type {RuntimeModule} */ (oldModule)) + ) { + cgc.dependentHashModules.delete( + /** @type {RuntimeModule} */ (oldModule) + ); + cgc.dependentHashModules.add( + /** @type {RuntimeModule} */ (newModule) + ); + } + } + oldCgm.runtimeInChunks = undefined; + } + } + + /** + * @param {Module} module the checked module + * @param {Chunk} chunk the checked chunk + * @returns {boolean} true, if the chunk contains the module + */ + isModuleInChunk(module, chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.has(module); + } + + /** + * @param {Module} module the checked module + * @param {ChunkGroup} chunkGroup the checked chunk group + * @returns {boolean} true, if the chunk contains the module + */ + isModuleInChunkGroup(module, chunkGroup) { + for (const chunk of chunkGroup.chunks) { + if (this.isModuleInChunk(module, chunk)) return true; + } + return false; + } + + /** + * @param {Module} module the checked module + * @returns {boolean} true, if the module is entry of any chunk + */ + isEntryModule(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.entryInChunks !== undefined; + } + + /** + * @param {Module} module the module + * @returns {Iterable<Chunk>} iterable of chunks (do not modify) + */ + getModuleChunksIterable(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.chunks; + } + + /** + * @param {Module} module the module + * @param {function(Chunk, Chunk): -1|0|1} sortFn sort function + * @returns {Iterable<Chunk>} iterable of chunks (do not modify) + */ + getOrderedModuleChunksIterable(module, sortFn) { + const cgm = this._getChunkGraphModule(module); + cgm.chunks.sortWith(sortFn); + return cgm.chunks; + } + + /** + * @param {Module} module the module + * @returns {Chunk[]} array of chunks (cached, do not modify) + */ + getModuleChunks(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.chunks.getFromCache(getArray); + } + + /** + * @param {Module} module the module + * @returns {number} the number of chunk which contain the module + */ + getNumberOfModuleChunks(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.chunks.size; + } + + /** + * @param {Module} module the module + * @returns {RuntimeSpecSet} runtimes + */ + getModuleRuntimes(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.chunks.getFromUnorderedCache(getModuleRuntimes); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {number} the number of modules which are contained in this chunk + */ + getNumberOfChunkModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.size; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {number} the number of full hash modules which are contained in this chunk + */ + getNumberOfChunkFullHashModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.fullHashModules === undefined ? 0 : cgc.fullHashModules.size; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<Module>} return the modules for this chunk + */ + getChunkModulesIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules; + } + + /** + * @param {Chunk} chunk the chunk + * @param {string} sourceType source type + * @returns {Iterable<Module> | undefined} return the modules for this chunk + */ + getChunkModulesIterableBySourceType(chunk, sourceType) { + const cgc = this._getChunkGraphChunk(chunk); + const modulesWithSourceType = cgc.modules + .getFromUnorderedCache(cgc._modulesBySourceType) + .get(sourceType); + return modulesWithSourceType; + } + + /** + * @param {Chunk} chunk chunk + * @param {Module} module chunk module + * @param {Set<string>} sourceTypes source types + */ + setChunkModuleSourceTypes(chunk, module, sourceTypes) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.sourceTypesByModule === undefined) { + cgc.sourceTypesByModule = new WeakMap(); + } + cgc.sourceTypesByModule.set(module, sourceTypes); + // Update cgc._modulesBySourceType to invalidate the cache + cgc._modulesBySourceType = modulesBySourceType(cgc.sourceTypesByModule); + } + + /** + * @param {Chunk} chunk chunk + * @param {Module} module chunk module + * @returns {Set<string>} source types + */ + getChunkModuleSourceTypes(chunk, module) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.sourceTypesByModule === undefined) { + return module.getSourceTypes(); + } + return cgc.sourceTypesByModule.get(module) || module.getSourceTypes(); + } + + /** + * @param {Module} module module + * @returns {Set<string>} source types + */ + getModuleSourceTypes(module) { + return ( + this._getOverwrittenModuleSourceTypes(module) || module.getSourceTypes() + ); + } + + /** + * @param {Module} module module + * @returns {Set<string> | undefined} source types + */ + _getOverwrittenModuleSourceTypes(module) { + let newSet = false; + let sourceTypes; + for (const chunk of this.getModuleChunksIterable(module)) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.sourceTypesByModule === undefined) return; + const st = cgc.sourceTypesByModule.get(module); + if (st === undefined) return; + if (!sourceTypes) { + sourceTypes = st; + continue; + } else if (!newSet) { + for (const type of st) { + if (!newSet) { + if (!sourceTypes.has(type)) { + newSet = true; + sourceTypes = new Set(sourceTypes); + sourceTypes.add(type); + } + } else { + sourceTypes.add(type); + } + } + } else { + for (const type of st) sourceTypes.add(type); + } + } + + return sourceTypes; + } + + /** + * @param {Chunk} chunk the chunk + * @param {function(Module, Module): -1|0|1} comparator comparator function + * @returns {Iterable<Module>} return the modules for this chunk + */ + getOrderedChunkModulesIterable(chunk, comparator) { + const cgc = this._getChunkGraphChunk(chunk); + cgc.modules.sortWith(comparator); + return cgc.modules; + } + + /** + * @param {Chunk} chunk the chunk + * @param {string} sourceType source type + * @param {function(Module, Module): -1|0|1} comparator comparator function + * @returns {Iterable<Module> | undefined} return the modules for this chunk + */ + getOrderedChunkModulesIterableBySourceType(chunk, sourceType, comparator) { + const cgc = this._getChunkGraphChunk(chunk); + const modulesWithSourceType = cgc.modules + .getFromUnorderedCache(cgc._modulesBySourceType) + .get(sourceType); + if (modulesWithSourceType === undefined) return undefined; + modulesWithSourceType.sortWith(comparator); + return modulesWithSourceType; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Module[]} return the modules for this chunk (cached, do not modify) + */ + getChunkModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.getFromUnorderedCache(getArray); + } + + /** + * @param {Chunk} chunk the chunk + * @param {function(Module, Module): -1|0|1} comparator comparator function + * @returns {Module[]} return the modules for this chunk (cached, do not modify) + */ + getOrderedChunkModules(chunk, comparator) { + const cgc = this._getChunkGraphChunk(chunk); + const arrayFunction = createOrderedArrayFunction(comparator); + return cgc.modules.getFromUnorderedCache(arrayFunction); + } + + /** + * @param {Chunk} chunk the chunk + * @param {ModuleFilterPredicate} filterFn function used to filter modules + * @param {boolean} includeAllChunks all chunks or only async chunks + * @returns {Record<string|number, (string|number)[]>} chunk to module ids object + */ + getChunkModuleIdMap(chunk, filterFn, includeAllChunks = false) { + /** @type {Record<string|number, (string|number)[]>} */ + const chunkModuleIdMap = Object.create(null); + + for (const asyncChunk of includeAllChunks + ? chunk.getAllReferencedChunks() + : chunk.getAllAsyncChunks()) { + /** @type {(string|number)[]} */ + let array; + for (const module of this.getOrderedChunkModulesIterable( + asyncChunk, + compareModulesById(this) + )) { + if (filterFn(module)) { + if (array === undefined) { + array = []; + chunkModuleIdMap[asyncChunk.id] = array; + } + const moduleId = this.getModuleId(module); + array.push(moduleId); + } + } + } + + return chunkModuleIdMap; + } + + /** + * @param {Chunk} chunk the chunk + * @param {ModuleFilterPredicate} filterFn function used to filter modules + * @param {number} hashLength length of the hash + * @param {boolean} includeAllChunks all chunks or only async chunks + * @returns {Record<string|number, Record<string|number, string>>} chunk to module id to module hash object + */ + getChunkModuleRenderedHashMap( + chunk, + filterFn, + hashLength = 0, + includeAllChunks = false + ) { + /** @type {Record<string|number, Record<string|number, string>>} */ + const chunkModuleHashMap = Object.create(null); + + for (const asyncChunk of includeAllChunks + ? chunk.getAllReferencedChunks() + : chunk.getAllAsyncChunks()) { + /** @type {Record<string|number, string>} */ + let idToHashMap; + for (const module of this.getOrderedChunkModulesIterable( + asyncChunk, + compareModulesById(this) + )) { + if (filterFn(module)) { + if (idToHashMap === undefined) { + idToHashMap = Object.create(null); + chunkModuleHashMap[asyncChunk.id] = idToHashMap; + } + const moduleId = this.getModuleId(module); + const hash = this.getRenderedModuleHash(module, asyncChunk.runtime); + idToHashMap[moduleId] = hashLength ? hash.slice(0, hashLength) : hash; + } + } + } + + return chunkModuleHashMap; + } + + /** + * @param {Chunk} chunk the chunk + * @param {ChunkFilterPredicate} filterFn function used to filter chunks + * @returns {Record<string|number, boolean>} chunk map + */ + getChunkConditionMap(chunk, filterFn) { + const map = Object.create(null); + for (const c of chunk.getAllReferencedChunks()) { + map[c.id] = filterFn(c, this); + } + return map; + } + + /** + * @param {Chunk} chunk the chunk + * @param {ModuleFilterPredicate} filterFn predicate function used to filter modules + * @param {ChunkFilterPredicate=} filterChunkFn predicate function used to filter chunks + * @returns {boolean} return true if module exists in graph + */ + hasModuleInGraph(chunk, filterFn, filterChunkFn) { + const queue = new Set(chunk.groupsIterable); + const chunksProcessed = new Set(); + + for (const chunkGroup of queue) { + for (const innerChunk of chunkGroup.chunks) { + if (!chunksProcessed.has(innerChunk)) { + chunksProcessed.add(innerChunk); + if (!filterChunkFn || filterChunkFn(innerChunk, this)) { + for (const module of this.getChunkModulesIterable(innerChunk)) { + if (filterFn(module)) { + return true; + } + } + } + } + } + for (const child of chunkGroup.childrenIterable) { + queue.add(child); + } + } + return false; + } + + /** + * @param {Chunk} chunkA first chunk + * @param {Chunk} chunkB second chunk + * @returns {-1|0|1} this is a comparator function like sort and returns -1, 0, or 1 based on sort order + */ + compareChunks(chunkA, chunkB) { + const cgcA = this._getChunkGraphChunk(chunkA); + const cgcB = this._getChunkGraphChunk(chunkB); + if (cgcA.modules.size > cgcB.modules.size) return -1; + if (cgcA.modules.size < cgcB.modules.size) return 1; + cgcA.modules.sortWith(compareModulesByIdentifier); + cgcB.modules.sortWith(compareModulesByIdentifier); + return compareModuleIterables(cgcA.modules, cgcB.modules); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {number} total size of all modules in the chunk + */ + getChunkModulesSize(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.getFromUnorderedCache(getModulesSize); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Record<string, number>} total sizes of all modules in the chunk by source type + */ + getChunkModulesSizes(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.getFromUnorderedCache(getModulesSizes); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Module[]} root modules of the chunks (ordered by identifier) + */ + getChunkRootModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.modules.getFromUnorderedCache(this._getGraphRoots); + } + + /** + * @param {Chunk} chunk the chunk + * @param {ChunkSizeOptions} options options object + * @returns {number} total size of the chunk + */ + getChunkSize(chunk, options = {}) { + const cgc = this._getChunkGraphChunk(chunk); + const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize); + const chunkOverhead = + typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000; + const entryChunkMultiplicator = + typeof options.entryChunkMultiplicator === "number" + ? options.entryChunkMultiplicator + : 10; + return ( + chunkOverhead + + modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1) + ); + } + + /** + * @param {Chunk} chunkA chunk + * @param {Chunk} chunkB chunk + * @param {ChunkSizeOptions} options options object + * @returns {number} total size of the chunk or false if chunks can't be integrated + */ + getIntegratedChunksSize(chunkA, chunkB, options = {}) { + const cgcA = this._getChunkGraphChunk(chunkA); + const cgcB = this._getChunkGraphChunk(chunkB); + const allModules = new Set(cgcA.modules); + for (const m of cgcB.modules) allModules.add(m); + let modulesSize = getModulesSize(allModules); + const chunkOverhead = + typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000; + const entryChunkMultiplicator = + typeof options.entryChunkMultiplicator === "number" + ? options.entryChunkMultiplicator + : 10; + return ( + chunkOverhead + + modulesSize * + (chunkA.canBeInitial() || chunkB.canBeInitial() + ? entryChunkMultiplicator + : 1) + ); + } + + /** + * @param {Chunk} chunkA chunk + * @param {Chunk} chunkB chunk + * @returns {boolean} true, if chunks could be integrated + */ + canChunksBeIntegrated(chunkA, chunkB) { + if (chunkA.preventIntegration || chunkB.preventIntegration) { + return false; + } + + const hasRuntimeA = chunkA.hasRuntime(); + const hasRuntimeB = chunkB.hasRuntime(); + + if (hasRuntimeA !== hasRuntimeB) { + if (hasRuntimeA) { + return isAvailableChunk(chunkA, chunkB); + } else if (hasRuntimeB) { + return isAvailableChunk(chunkB, chunkA); + } else { + return false; + } + } + + if ( + this.getNumberOfEntryModules(chunkA) > 0 || + this.getNumberOfEntryModules(chunkB) > 0 + ) { + return false; + } + + return true; + } + + /** + * @param {Chunk} chunkA the target chunk + * @param {Chunk} chunkB the chunk to integrate + * @returns {void} + */ + integrateChunks(chunkA, chunkB) { + // Decide for one name (deterministic) + if (chunkA.name && chunkB.name) { + if ( + this.getNumberOfEntryModules(chunkA) > 0 === + this.getNumberOfEntryModules(chunkB) > 0 + ) { + // When both chunks have entry modules or none have one, use + // shortest name + if (chunkA.name.length !== chunkB.name.length) { + chunkA.name = + chunkA.name.length < chunkB.name.length ? chunkA.name : chunkB.name; + } else { + chunkA.name = chunkA.name < chunkB.name ? chunkA.name : chunkB.name; + } + } else if (this.getNumberOfEntryModules(chunkB) > 0) { + // Pick the name of the chunk with the entry module + chunkA.name = chunkB.name; + } + } else if (chunkB.name) { + chunkA.name = chunkB.name; + } + + // Merge id name hints + for (const hint of chunkB.idNameHints) { + chunkA.idNameHints.add(hint); + } + + // Merge runtime + chunkA.runtime = mergeRuntime(chunkA.runtime, chunkB.runtime); + + // getChunkModules is used here to create a clone, because disconnectChunkAndModule modifies + for (const module of this.getChunkModules(chunkB)) { + this.disconnectChunkAndModule(chunkB, module); + this.connectChunkAndModule(chunkA, module); + } + + for (const [module, chunkGroup] of Array.from( + this.getChunkEntryModulesWithChunkGroupIterable(chunkB) + )) { + this.disconnectChunkAndEntryModule(chunkB, module); + this.connectChunkAndEntryModule(chunkA, module, chunkGroup); + } + + for (const chunkGroup of chunkB.groupsIterable) { + chunkGroup.replaceChunk(chunkB, chunkA); + chunkA.addGroup(chunkGroup); + chunkB.removeGroup(chunkGroup); + } + ChunkGraph.clearChunkGraphForChunk(chunkB); + } + + /** + * @param {Chunk} chunk the chunk to upgrade + * @returns {void} + */ + upgradeDependentToFullHashModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.dependentHashModules === undefined) return; + if (cgc.fullHashModules === undefined) { + cgc.fullHashModules = cgc.dependentHashModules; + } else { + for (const m of cgc.dependentHashModules) { + cgc.fullHashModules.add(m); + } + cgc.dependentHashModules = undefined; + } + } + + /** + * @param {Module} module the checked module + * @param {Chunk} chunk the checked chunk + * @returns {boolean} true, if the chunk contains the module as entry + */ + isEntryModuleInChunk(module, chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.entryModules.has(module); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {Module} module the entry module + * @param {Entrypoint=} entrypoint the chunk group which must be loaded before the module is executed + * @returns {void} + */ + connectChunkAndEntryModule(chunk, module, entrypoint) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + if (cgm.entryInChunks === undefined) { + cgm.entryInChunks = new Set(); + } + cgm.entryInChunks.add(chunk); + cgc.entryModules.set(module, entrypoint); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {RuntimeModule} module the runtime module + * @returns {void} + */ + connectChunkAndRuntimeModule(chunk, module) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + if (cgm.runtimeInChunks === undefined) { + cgm.runtimeInChunks = new Set(); + } + cgm.runtimeInChunks.add(chunk); + cgc.runtimeModules.add(module); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {RuntimeModule} module the module that require a full hash + * @returns {void} + */ + addFullHashModuleToChunk(chunk, module) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set(); + cgc.fullHashModules.add(module); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {RuntimeModule} module the module that require a full hash + * @returns {void} + */ + addDependentHashModuleToChunk(chunk, module) { + const cgc = this._getChunkGraphChunk(chunk); + if (cgc.dependentHashModules === undefined) + cgc.dependentHashModules = new Set(); + cgc.dependentHashModules.add(module); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {Module} module the entry module + * @returns {void} + */ + disconnectChunkAndEntryModule(chunk, module) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + cgm.entryInChunks.delete(chunk); + if (cgm.entryInChunks.size === 0) { + cgm.entryInChunks = undefined; + } + cgc.entryModules.delete(module); + } + + /** + * @param {Chunk} chunk the new chunk + * @param {RuntimeModule} module the runtime module + * @returns {void} + */ + disconnectChunkAndRuntimeModule(chunk, module) { + const cgm = this._getChunkGraphModule(module); + const cgc = this._getChunkGraphChunk(chunk); + cgm.runtimeInChunks.delete(chunk); + if (cgm.runtimeInChunks.size === 0) { + cgm.runtimeInChunks = undefined; + } + cgc.runtimeModules.delete(module); + } + + /** + * @param {Module} module the entry module, it will no longer be entry + * @returns {void} + */ + disconnectEntryModule(module) { + const cgm = this._getChunkGraphModule(module); + for (const chunk of cgm.entryInChunks) { + const cgc = this._getChunkGraphChunk(chunk); + cgc.entryModules.delete(module); + } + cgm.entryInChunks = undefined; + } + + /** + * @param {Chunk} chunk the chunk, for which all entries will be removed + * @returns {void} + */ + disconnectEntries(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + for (const module of cgc.entryModules.keys()) { + const cgm = this._getChunkGraphModule(module); + cgm.entryInChunks.delete(chunk); + if (cgm.entryInChunks.size === 0) { + cgm.entryInChunks = undefined; + } + } + cgc.entryModules.clear(); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {number} the amount of entry modules in chunk + */ + getNumberOfEntryModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.entryModules.size; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {number} the amount of entry modules in chunk + */ + getNumberOfRuntimeModules(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.runtimeModules.size; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<Module>} iterable of modules (do not modify) + */ + getChunkEntryModulesIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.entryModules.keys(); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<Chunk>} iterable of chunks + */ + getChunkEntryDependentChunksIterable(chunk) { + /** @type {Set<Chunk>} */ + const set = new Set(); + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup instanceof Entrypoint) { + const entrypointChunk = chunkGroup.getEntrypointChunk(); + const cgc = this._getChunkGraphChunk(entrypointChunk); + for (const chunkGroup of cgc.entryModules.values()) { + for (const c of chunkGroup.chunks) { + if (c !== chunk && c !== entrypointChunk && !c.hasRuntime()) { + set.add(c); + } + } + } + } + } + + return set; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {boolean} true, when it has dependent chunks + */ + hasChunkEntryDependentChunks(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + for (const chunkGroup of cgc.entryModules.values()) { + for (const c of chunkGroup.chunks) { + if (c !== chunk) { + return true; + } + } + } + return false; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<RuntimeModule>} iterable of modules (do not modify) + */ + getChunkRuntimeModulesIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.runtimeModules; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {RuntimeModule[]} array of modules in order of execution + */ + getChunkRuntimeModulesInOrder(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + const array = Array.from(cgc.runtimeModules); + array.sort( + concatComparators( + compareSelect( + /** + * @param {RuntimeModule} r runtime module + * @returns {number=} stage + */ + r => r.stage, + compareIds + ), + compareModulesByIdentifier + ) + ); + return array; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify) + */ + getChunkFullHashModulesIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.fullHashModules; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {ReadonlySet<RuntimeModule> | undefined} set of modules (do not modify) + */ + getChunkFullHashModulesSet(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.fullHashModules; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify) + */ + getChunkDependentHashModulesIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.dependentHashModules; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {Iterable<EntryModuleWithChunkGroup>} iterable of modules (do not modify) + */ + getChunkEntryModulesWithChunkGroupIterable(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.entryModules; + } + + /** + * @param {AsyncDependenciesBlock} depBlock the async block + * @returns {ChunkGroup} the chunk group + */ + getBlockChunkGroup(depBlock) { + return this._blockChunkGroups.get(depBlock); + } + + /** + * @param {AsyncDependenciesBlock} depBlock the async block + * @param {ChunkGroup} chunkGroup the chunk group + * @returns {void} + */ + connectBlockAndChunkGroup(depBlock, chunkGroup) { + this._blockChunkGroups.set(depBlock, chunkGroup); + chunkGroup.addBlock(depBlock); + } + + /** + * @param {ChunkGroup} chunkGroup the chunk group + * @returns {void} + */ + disconnectChunkGroup(chunkGroup) { + for (const block of chunkGroup.blocksIterable) { + this._blockChunkGroups.delete(block); + } + // TODO refactor by moving blocks list into ChunkGraph + chunkGroup._blocks.clear(); + } + + /** + * @param {Module} module the module + * @returns {string | number} the id of the module + */ + getModuleId(module) { + const cgm = this._getChunkGraphModule(module); + return cgm.id; + } + + /** + * @param {Module} module the module + * @param {string | number} id the id of the module + * @returns {void} + */ + setModuleId(module, id) { + const cgm = this._getChunkGraphModule(module); + cgm.id = id; + } + + /** + * @param {string} runtime runtime + * @returns {string | number} the id of the runtime + */ + getRuntimeId(runtime) { + return this._runtimeIds.get(runtime); + } + + /** + * @param {string} runtime runtime + * @param {string | number} id the id of the runtime + * @returns {void} + */ + setRuntimeId(runtime, id) { + this._runtimeIds.set(runtime, id); + } + + /** + * @template T + * @param {Module} module the module + * @param {RuntimeSpecMap<T>} hashes hashes data + * @param {RuntimeSpec} runtime the runtime + * @returns {T} hash + */ + _getModuleHashInfo(module, hashes, runtime) { + if (!hashes) { + throw new Error( + `Module ${module.identifier()} has no hash info for runtime ${runtimeToString( + runtime + )} (hashes not set at all)` + ); + } else if (runtime === undefined) { + const hashInfoItems = new Set(hashes.values()); + if (hashInfoItems.size !== 1) { + throw new Error( + `No unique hash info entry for unspecified runtime for ${module.identifier()} (existing runtimes: ${Array.from( + hashes.keys(), + r => runtimeToString(r) + ).join(", ")}). +Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").` + ); + } + return first(hashInfoItems); + } else { + const hashInfo = hashes.get(runtime); + if (!hashInfo) { + throw new Error( + `Module ${module.identifier()} has no hash info for runtime ${runtimeToString( + runtime + )} (available runtimes ${Array.from( + hashes.keys(), + runtimeToString + ).join(", ")})` + ); + } + return hashInfo; + } + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {boolean} true, if the module has hashes for this runtime + */ + hasModuleHashes(module, runtime) { + const cgm = this._getChunkGraphModule(module); + const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes); + return hashes && hashes.has(runtime); + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {string} hash + */ + getModuleHash(module, runtime) { + const cgm = this._getChunkGraphModule(module); + const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes); + return this._getModuleHashInfo(module, hashes, runtime).hash; + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {string} hash + */ + getRenderedModuleHash(module, runtime) { + const cgm = this._getChunkGraphModule(module); + const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes); + return this._getModuleHashInfo(module, hashes, runtime).renderedHash; + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @param {string} hash the full hash + * @param {string} renderedHash the shortened hash for rendering + * @returns {void} + */ + setModuleHashes(module, runtime, hash, renderedHash) { + const cgm = this._getChunkGraphModule(module); + if (cgm.hashes === undefined) { + cgm.hashes = new RuntimeSpecMap(); + } + cgm.hashes.set(runtime, new ModuleHashInfo(hash, renderedHash)); + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph when transferOwnership not false) + * @param {boolean} transferOwnership true: transfer ownership of the items object, false: items is immutable and shared and won't be modified + * @returns {void} + */ + addModuleRuntimeRequirements( + module, + runtime, + items, + transferOwnership = true + ) { + const cgm = this._getChunkGraphModule(module); + const runtimeRequirementsMap = cgm.runtimeRequirements; + if (runtimeRequirementsMap === undefined) { + const map = new RuntimeSpecMap(); + // TODO avoid cloning item and track ownership instead + map.set(runtime, transferOwnership ? items : new Set(items)); + cgm.runtimeRequirements = map; + return; + } + runtimeRequirementsMap.update(runtime, runtimeRequirements => { + if (runtimeRequirements === undefined) { + return transferOwnership ? items : new Set(items); + } else if (!transferOwnership || runtimeRequirements.size >= items.size) { + for (const item of items) runtimeRequirements.add(item); + return runtimeRequirements; + } else { + for (const item of runtimeRequirements) items.add(item); + return items; + } + }); + } + + /** + * @param {Chunk} chunk the chunk + * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph) + * @returns {void} + */ + addChunkRuntimeRequirements(chunk, items) { + const cgc = this._getChunkGraphChunk(chunk); + const runtimeRequirements = cgc.runtimeRequirements; + if (runtimeRequirements === undefined) { + cgc.runtimeRequirements = items; + } else if (runtimeRequirements.size >= items.size) { + for (const item of items) runtimeRequirements.add(item); + } else { + for (const item of runtimeRequirements) items.add(item); + cgc.runtimeRequirements = items; + } + } + + /** + * @param {Chunk} chunk the chunk + * @param {Iterable<string>} items runtime requirements to be added + * @returns {void} + */ + addTreeRuntimeRequirements(chunk, items) { + const cgc = this._getChunkGraphChunk(chunk); + const runtimeRequirements = cgc.runtimeRequirementsInTree; + for (const item of items) runtimeRequirements.add(item); + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {ReadonlySet<string>} runtime requirements + */ + getModuleRuntimeRequirements(module, runtime) { + const cgm = this._getChunkGraphModule(module); + const runtimeRequirements = + cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime); + return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements; + } + + /** + * @param {Chunk} chunk the chunk + * @returns {ReadonlySet<string>} runtime requirements + */ + getChunkRuntimeRequirements(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + const runtimeRequirements = cgc.runtimeRequirements; + return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements; + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @param {boolean} withConnections include connections + * @returns {string} hash + */ + getModuleGraphHash(module, runtime, withConnections = true) { + const cgm = this._getChunkGraphModule(module); + return withConnections + ? this._getModuleGraphHashWithConnections(cgm, module, runtime) + : this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16); + } + + /** + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @param {boolean} withConnections include connections + * @returns {bigint} hash + */ + getModuleGraphHashBigInt(module, runtime, withConnections = true) { + const cgm = this._getChunkGraphModule(module); + return withConnections + ? BigInt( + `0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}` + ) + : this._getModuleGraphHashBigInt(cgm, module, runtime); + } + + /** + * @param {ChunkGraphModule} cgm the ChunkGraphModule + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {bigint} hash as big int + */ + _getModuleGraphHashBigInt(cgm, module, runtime) { + if (cgm.graphHashes === undefined) { + cgm.graphHashes = new RuntimeSpecMap(); + } + const graphHash = cgm.graphHashes.provide(runtime, () => { + const hash = createHash(this._hashFunction); + hash.update(`${cgm.id}${this.moduleGraph.isAsync(module)}`); + const sourceTypes = this._getOverwrittenModuleSourceTypes(module); + if (sourceTypes !== undefined) { + for (const type of sourceTypes) hash.update(type); + } + this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime); + return BigInt(`0x${/** @type {string} */ (hash.digest("hex"))}`); + }); + return graphHash; + } + + /** + * @param {ChunkGraphModule} cgm the ChunkGraphModule + * @param {Module} module the module + * @param {RuntimeSpec} runtime the runtime + * @returns {string} hash + */ + _getModuleGraphHashWithConnections(cgm, module, runtime) { + if (cgm.graphHashesWithConnections === undefined) { + cgm.graphHashesWithConnections = new RuntimeSpecMap(); + } + const activeStateToString = state => { + if (state === false) return "F"; + if (state === true) return "T"; + if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O"; + throw new Error("Not implemented active state"); + }; + const strict = module.buildMeta && module.buildMeta.strictHarmonyModule; + return cgm.graphHashesWithConnections.provide(runtime, () => { + const graphHash = this._getModuleGraphHashBigInt( + cgm, + module, + runtime + ).toString(16); + const connections = this.moduleGraph.getOutgoingConnections(module); + /** @type {Set<Module>} */ + const activeNamespaceModules = new Set(); + /** @type {Map<string, Module | Set<Module>>} */ + const connectedModules = new Map(); + const processConnection = (connection, stateInfo) => { + const module = connection.module; + stateInfo += module.getExportsType(this.moduleGraph, strict); + // cspell:word Tnamespace + if (stateInfo === "Tnamespace") activeNamespaceModules.add(module); + else { + const oldModule = connectedModules.get(stateInfo); + if (oldModule === undefined) { + connectedModules.set(stateInfo, module); + } else if (oldModule instanceof Set) { + oldModule.add(module); + } else if (oldModule !== module) { + connectedModules.set(stateInfo, new Set([oldModule, module])); + } + } + }; + if (runtime === undefined || typeof runtime === "string") { + for (const connection of connections) { + const state = connection.getActiveState(runtime); + if (state === false) continue; + processConnection(connection, state === true ? "T" : "O"); + } + } else { + // cspell:word Tnamespace + for (const connection of connections) { + const states = new Set(); + let stateInfo = ""; + forEachRuntime( + runtime, + runtime => { + const state = connection.getActiveState(runtime); + states.add(state); + stateInfo += activeStateToString(state) + runtime; + }, + true + ); + if (states.size === 1) { + const state = first(states); + if (state === false) continue; + stateInfo = activeStateToString(state); + } + processConnection(connection, stateInfo); + } + } + // cspell:word Tnamespace + if (activeNamespaceModules.size === 0 && connectedModules.size === 0) + return graphHash; + const connectedModulesInOrder = + connectedModules.size > 1 + ? Array.from(connectedModules).sort(([a], [b]) => (a < b ? -1 : 1)) + : connectedModules; + const hash = createHash(this._hashFunction); + const addModuleToHash = module => { + hash.update( + this._getModuleGraphHashBigInt( + this._getChunkGraphModule(module), + module, + runtime + ).toString(16) + ); + }; + const addModulesToHash = modules => { + let xor = ZERO_BIG_INT; + for (const m of modules) { + xor = + xor ^ + this._getModuleGraphHashBigInt( + this._getChunkGraphModule(m), + m, + runtime + ); + } + hash.update(xor.toString(16)); + }; + if (activeNamespaceModules.size === 1) + addModuleToHash(activeNamespaceModules.values().next().value); + else if (activeNamespaceModules.size > 1) + addModulesToHash(activeNamespaceModules); + for (const [stateInfo, modules] of connectedModulesInOrder) { + hash.update(stateInfo); + if (modules instanceof Set) { + addModulesToHash(modules); + } else { + addModuleToHash(modules); + } + } + hash.update(graphHash); + return /** @type {string} */ (hash.digest("hex")); + }); + } + + /** + * @param {Chunk} chunk the chunk + * @returns {ReadonlySet<string>} runtime requirements + */ + getTreeRuntimeRequirements(chunk) { + const cgc = this._getChunkGraphChunk(chunk); + return cgc.runtimeRequirementsInTree; + } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {string} deprecateMessage message for the deprecation message + * @param {string} deprecationCode code for the deprecation + * @returns {ChunkGraph} the chunk graph + */ + static getChunkGraphForModule(module, deprecateMessage, deprecationCode) { + const fn = deprecateGetChunkGraphForModuleMap.get(deprecateMessage); + if (fn) return fn(module); + const newFn = util.deprecate( + /** + * @param {Module} module the module + * @returns {ChunkGraph} the chunk graph + */ + module => { + const chunkGraph = chunkGraphForModuleMap.get(module); + if (!chunkGraph) + throw new Error( + deprecateMessage + + ": There was no ChunkGraph assigned to the Module for backward-compat (Use the new API)" + ); + return chunkGraph; + }, + deprecateMessage + ": Use new ChunkGraph API", + deprecationCode + ); + deprecateGetChunkGraphForModuleMap.set(deprecateMessage, newFn); + return newFn(module); + } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {ChunkGraph} chunkGraph the chunk graph + * @returns {void} + */ + static setChunkGraphForModule(module, chunkGraph) { + chunkGraphForModuleMap.set(module, chunkGraph); + } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @returns {void} + */ + static clearChunkGraphForModule(module) { + chunkGraphForModuleMap.delete(module); + } + + // TODO remove in webpack 6 + /** + * @param {Chunk} chunk the chunk + * @param {string} deprecateMessage message for the deprecation message + * @param {string} deprecationCode code for the deprecation + * @returns {ChunkGraph} the chunk graph + */ + static getChunkGraphForChunk(chunk, deprecateMessage, deprecationCode) { + const fn = deprecateGetChunkGraphForChunkMap.get(deprecateMessage); + if (fn) return fn(chunk); + const newFn = util.deprecate( + /** + * @param {Chunk} chunk the chunk + * @returns {ChunkGraph} the chunk graph + */ + chunk => { + const chunkGraph = chunkGraphForChunkMap.get(chunk); + if (!chunkGraph) + throw new Error( + deprecateMessage + + "There was no ChunkGraph assigned to the Chunk for backward-compat (Use the new API)" + ); + return chunkGraph; + }, + deprecateMessage + ": Use new ChunkGraph API", + deprecationCode + ); + deprecateGetChunkGraphForChunkMap.set(deprecateMessage, newFn); + return newFn(chunk); + } + + // TODO remove in webpack 6 + /** + * @param {Chunk} chunk the chunk + * @param {ChunkGraph} chunkGraph the chunk graph + * @returns {void} + */ + static setChunkGraphForChunk(chunk, chunkGraph) { + chunkGraphForChunkMap.set(chunk, chunkGraph); + } + + // TODO remove in webpack 6 + /** + * @param {Chunk} chunk the chunk + * @returns {void} + */ + static clearChunkGraphForChunk(chunk) { + chunkGraphForChunkMap.delete(chunk); + } +} + +// TODO remove in webpack 6 +/** @type {WeakMap<Module, ChunkGraph>} */ +const chunkGraphForModuleMap = new WeakMap(); + +// TODO remove in webpack 6 +/** @type {WeakMap<Chunk, ChunkGraph>} */ +const chunkGraphForChunkMap = new WeakMap(); + +// TODO remove in webpack 6 +/** @type {Map<string, (module: Module) => ChunkGraph>} */ +const deprecateGetChunkGraphForModuleMap = new Map(); + +// TODO remove in webpack 6 +/** @type {Map<string, (chunk: Chunk) => ChunkGraph>} */ +const deprecateGetChunkGraphForChunkMap = new Map(); + +module.exports = ChunkGraph; |
