✅ 模块与 Chunk 的运行时需求处理
-
addModuleRuntimeRequirements
- 为模块添加运行时依赖项。
- 支持“所有权转移”机制,以优化性能(避免 Set 拷贝)。
- 若该 runtime 尚未有依赖,则直接设置;若已存在则合并集合(智能合并较小集合到较大集合中)。
-
addChunkRuntimeRequirements
- 为 Chunk 添加运行时依赖项。
- 同样采用了大小判断合并策略,优化内存和性能。
-
addTreeRuntimeRequirements
- 向 chunk 所在的整个 chunk 树添加运行时需求项。
- 用于处理跨 chunk 的树状依赖需求。
🔍 运行时需求的读取
🧮 模块图哈希计算
addModuleRuntimeRequirements(
module,
runtime,
items,
transferOwnership = true
) {
const cgm = this._getChunkGraphModule(module);
const runtimeRequirementsMap = cgm.runtimeRequirements;
if (runtimeRequirementsMap === undefined) {
const map = new RuntimeSpecMap();
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;
}
for (const item of runtimeRequirements) items.add(item);
return items;
});
}
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;
}
}
addTreeRuntimeRequirements(chunk, items) {
const cgc = this._getChunkGraphChunk(chunk);
const runtimeRequirements = cgc.runtimeRequirementsInTree;
for (const item of items) runtimeRequirements.add(item);
}
getModuleRuntimeRequirements(module, runtime) {
const cgm = this._getChunkGraphModule(module);
const runtimeRequirements =
cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime);
return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
}
getChunkRuntimeRequirements(chunk) {
const cgc = this._getChunkGraphChunk(chunk);
const runtimeRequirements = cgc.runtimeRequirements;
return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
}
getModuleGraphHash(module, runtime, withConnections = true) {
const cgm = this._getChunkGraphModule(module);
return withConnections
? this._getModuleGraphHashWithConnections(cgm, module, runtime)
: this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16);
}
getModuleGraphHashBigInt(module, runtime, withConnections = true) {
const cgm = this._getChunkGraphModule(module);
return withConnections
? BigInt(
`0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}`
)
: this._getModuleGraphHashBigInt(cgm, module, runtime);
}
_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;
}