js
复制代码
/**
* 添加模块的运行时需求。
* @param {Module} module 要添加的模块
* @param {RuntimeSpec} runtime 运行时环境
* @param {Set<string>} items 要添加的运行时需求集合(所有权在 transferOwnership 不为 false 时将转移给 ChunkGraph)
* @param {boolean} transferOwnership 是否转移 items 的所有权(默认为 true)
*/
addModuleRuntimeRequirements(
module,
runtime,
items,
transferOwnership = true
) {
const cgm = this._getChunkGraphModule(module); // 获取模块对应的 ChunkGraphModule
const runtimeRequirementsMap = cgm.runtimeRequirements; // 获取模块的 runtime -> requirements 映射表
if (runtimeRequirementsMap === undefined) {
const map = new RuntimeSpecMap(); // 创建新的 RuntimeSpecMap 映射
// TODO: 避免复制集合,使用所有权转移方式提升性能
map.set(runtime, transferOwnership ? items : new Set(items)); // 设置 runtime 对应的需求集合
cgm.runtimeRequirements = map; // 存入 ChunkGraphModule 中
return;
}
// 更新已有 runtimeRequirementsMap 中对应 runtime 的需求集合
runtimeRequirementsMap.update(runtime, runtimeRequirements => {
if (runtimeRequirements === undefined) {
// 当前 runtime 尚无需求,直接设为 items(如果转移所有权)或复制新集合
return transferOwnership ? items : new Set(items);
} else if (!transferOwnership || runtimeRequirements.size >= items.size) {
// 如果不转移所有权,或已有集合更大,合并 items 到已有集合中
for (const item of items) runtimeRequirements.add(item);
return runtimeRequirements;
}
// 否则将已有集合内容合并进 items 并返回 items(使用新的更大集合替换)
for (const item of runtimeRequirements) items.add(item);
return items;
});
}
/**
* 添加 chunk 的运行时需求。
* @param {Chunk} chunk 要添加的 chunk
* @param {Set<string>} items 所需运行时需求(所有权将转移给 ChunkGraph)
*/
addChunkRuntimeRequirements(chunk, items) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 Chunk 对应的 ChunkGraphChunk
const runtimeRequirements = cgc.runtimeRequirements; // 获取当前 chunk 的需求集合
if (runtimeRequirements === undefined) {
cgc.runtimeRequirements = items; // 若不存在,直接赋值
} else if (runtimeRequirements.size >= items.size) {
// 如果已有集合较大,将 items 添加进已有集合
for (const item of items) runtimeRequirements.add(item);
} else {
// 否则合并已有集合到 items,并替换引用
for (const item of runtimeRequirements) items.add(item);
cgc.runtimeRequirements = items;
}
}
/**
* 添加 chunk 树级别的运行时需求。
* @param {Chunk} chunk 当前 chunk
* @param {Iterable<string>} items 要添加的需求项
*/
addTreeRuntimeRequirements(chunk, items) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 Chunk 对应的 ChunkGraphChunk
const runtimeRequirements = cgc.runtimeRequirementsInTree; // 获取该 chunk 所在的 chunk tree 的运行时需求集合
for (const item of items) runtimeRequirements.add(item); // 逐个添加
}
/**
* 获取模块在某个 runtime 下的运行时需求。
* @param {Module} module 模块
* @param {RuntimeSpec} runtime 对应的运行时
* @returns {ReadOnlyRuntimeRequirements} 返回运行时需求集合,若无则返回空集合
*/
getModuleRuntimeRequirements(module, runtime) {
const cgm = this._getChunkGraphModule(module); // 获取 ChunkGraphModule 实例
const runtimeRequirements =
cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime); // 获取指定 runtime 的需求集合
return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements; // 若不存在则返回空集合
}
/**
* 获取 chunk 的运行时需求集合。
* @param {Chunk} chunk chunk 实例
* @returns {ReadOnlyRuntimeRequirements} 只读运行时需求集合
*/
getChunkRuntimeRequirements(chunk) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 ChunkGraphChunk 实例
const runtimeRequirements = cgc.runtimeRequirements; // 获取需求集合
return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
}
/**
* 获取模块在指定 runtime 下的模块图 hash(字符串形式)。
* @param {Module} module 模块
* @param {RuntimeSpec} runtime 运行时
* @param {boolean} withConnections 是否包含连接信息
* @returns {string} 返回模块图 hash 的十六进制字符串
*/
getModuleGraphHash(module, runtime, withConnections = true) {
const cgm = this._getChunkGraphModule(module); // 获取模块对应的 ChunkGraphModule
return withConnections
? this._getModuleGraphHashWithConnections(cgm, module, runtime) // 包含连接信息的 hash
: this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16); // 否则返回 bigint 的十六进制字符串
}
/**
* 获取模块在指定 runtime 下的模块图 hash(BigInt 形式)。
* @param {Module} module 模块
* @param {RuntimeSpec} runtime 运行时
* @param {boolean} withConnections 是否包含连接信息
* @returns {bigint} 模块图的 hash 值(BigInt 格式)
*/
getModuleGraphHashBigInt(module, runtime, withConnections = true) {
const cgm = this._getChunkGraphModule(module); // 获取模块对应的 ChunkGraphModule
return withConnections
? BigInt(
`0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}`
) // 若包含连接,先用 string 表示再转 BigInt
: this._getModuleGraphHashBigInt(cgm, module, runtime); // 否则调用内部实现直接获取 BigInt
}
/**
* 内部方法:真正计算模块的模块图 hash(BigInt 形式)。
* @param {ChunkGraphModule} cgm ChunkGraphModule 实例
* @param {Module} module 模块
* @param {RuntimeSpec} runtime 运行时
* @returns {bigint} 返回计算出的 hash 值
*/
_getModuleGraphHashBigInt(cgm, module, runtime) {
if (cgm.graphHashes === undefined) {
cgm.graphHashes = new RuntimeSpecMap(); // 初始化 graphHashes 映射
}
const graphHash = cgm.graphHashes.provide(runtime, () => {
const hash = createHash(this._hashFunction); // 创建 hash 实例(可能是 md4、sha256 等)
hash.update(`${cgm.id}${this.moduleGraph.isAsync(module)}`); // 将模块 ID 和异步标识加入 hash 中
const sourceTypes = this._getOverwrittenModuleSourceTypes(module); // 获取该模块的重写源类型
if (sourceTypes !== undefined) {
for (const type of sourceTypes) hash.update(type); // 将每个 source type 更新进 hash
}
this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime); // 将导出信息更新到 hash 中
return BigInt(`0x${/** @type {string} */ (hash.digest("hex"))}`); // 最终输出为十六进制 hash 字符串转为 BigInt
});
return graphHash;
}