🔄 integrateChunks(chunkA, chunkB)
-
合并两个 chunk 的内容,保留 chunkA,清除 chunkB。
-
决定合并后 chunk 的名称(基于 entry 和名称长度)。
-
合并:
idNameHintsruntime(使用mergeRuntime)- 模块:从 chunkB 断开并连接到 chunkA
- 入口模块及其所属 chunk group
- 所有 chunkGroup 中的 chunkB 替换为 chunkA
-
最后清除 chunkB 的所有图关系。
🔧 upgradeDependentToFullHashModules(chunk)
- 将 chunk 中的
dependentHashModules升级为fullHashModules。 - 如果
fullHashModules已存在,则进行集合合并。
🔍 isEntryModuleInChunk(module, chunk)
- 判断某个模块是否为 chunk 的入口模块。
- 通过
chunk.entryModules.has(module)直接判断。
➕ connectChunkAndEntryModule(chunk, module, entrypoint)
- 建立 chunk 与入口模块的关系。
- 记录模块在哪些 chunk 中是 entry(
entryInChunks)。 - 将模块及其入口点组记录到 chunk 的
entryModules。
➕ connectChunkAndRuntimeModule(chunk, module)
- 建立 chunk 与 runtime 模块的关系。
- 添加至模块的
runtimeInChunks和 chunk 的runtimeModules。
➕ addFullHashModuleToChunk(chunk, module)
- 向 chunk 添加一个 full hash 的 runtime 模块。
- 用于标记该模块在计算 chunk hash 时需要完整 hash。
➕ addDependentHashModuleToChunk(chunk, module)
- 向 chunk 添加一个 dependent hash 的 runtime 模块。
- 模块依赖于其它模块的 hash,而不需要完整 chunk 的 hash。
❌ disconnectChunkAndEntryModule(chunk, module)
- 断开 chunk 与某个入口模块的连接。
- 从模块的
entryInChunks中移除该 chunk。 - 若集合为空,清空引用。
- 同时从 chunk 的
entryModules中移除该模块。
❌ disconnectChunkAndRuntimeModule(chunk, module)
- 断开 chunk 与某个 runtime 模块的连接。
- 从模块的
runtimeInChunks中移除该 chunk。 - 若集合为空,清空引用。
- 同时从 chunk 的
runtimeModules中移除该模块。
/**
* 将 chunkB 的内容合并到 chunkA 中(包括模块、运行时代码、入口信息、group 等)
* @param {Chunk} chunkA 要合并到的目标 chunk
* @param {Chunk} chunkB 被合并的 chunk
*/
integrateChunks(chunkA, chunkB) {
// 决定合并后 chunk 的名称(确保具有确定性)
if (chunkA.name && chunkB.name) {
if (
this.getNumberOfEntryModules(chunkA) > 0 ===
this.getNumberOfEntryModules(chunkB) > 0
) {
// 如果两个 chunk 都有(或都没有)入口模块,则选用较短的名称
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) {
// 如果 chunkB 有 entry 而 chunkA 没有,使用 chunkB 的名称
chunkA.name = chunkB.name;
}
} else if (chunkB.name) {
// 若 chunkA 无名但 chunkB 有名,则直接采用 chunkB 的名称
chunkA.name = chunkB.name;
}
// 合并 chunkB 的名称提示(用于生成 chunk 名)
for (const hint of chunkB.idNameHints) {
chunkA.idNameHints.add(hint);
}
// 合并 runtime(如 runtime 名称或集合)
chunkA.runtime = mergeRuntime(chunkA.runtime, chunkB.runtime);
// 迁移 chunkB 中的模块到 chunkA
for (const module of this.getChunkModules(chunkB)) {
this.disconnectChunkAndModule(chunkB, module); // 从 chunkB 中断开模块
this.connectChunkAndModule(chunkA, module); // 将模块连接到 chunkA
}
// 迁移 chunkB 中的入口模块及其 chunkGroup
for (const [module, chunkGroup] of Array.from(
this.getChunkEntryModulesWithChunkGroupIterable(chunkB)
)) {
this.disconnectChunkAndEntryModule(chunkB, module); // 断开 chunkB 的 entry
this.connectChunkAndEntryModule(
chunkA,
module,
/** @type {Entrypoint} */ (chunkGroup)
); // 将 entry 接入 chunkA
}
// 将 chunkB 所在的 chunkGroup 中替换为 chunkA
for (const chunkGroup of chunkB.groupsIterable) {
chunkGroup.replaceChunk(chunkB, chunkA);
chunkA.addGroup(chunkGroup); // 加入 chunkA 的 group 引用
chunkB.removeGroup(chunkGroup); // 移除 chunkB 的 group 引用
}
// 清理 chunkB 的所有 chunk graph 关系
ChunkGraph.clearChunkGraphForChunk(chunkB);
}
/**
* 将 chunk 中依赖 hash 的模块提升为完全依赖 full hash 的模块
* @param {Chunk} chunk 要升级的 chunk
*/
upgradeDependentToFullHashModules(chunk) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 chunk 的 graph 节点
if (cgc.dependentHashModules === undefined) return; // 没有 dependent 模块则返回
if (cgc.fullHashModules === undefined) {
// 若 fullHashModules 尚未定义,直接赋值
cgc.fullHashModules = cgc.dependentHashModules;
} else {
// 否则合并集合
for (const m of cgc.dependentHashModules) {
cgc.fullHashModules.add(m);
}
cgc.dependentHashModules = undefined; // 清空 dependent 模块集合
}
}
/**
* 判断模块是否为某个 chunk 的入口模块
* @param {Module} module 检查的模块
* @param {Chunk} chunk 检查的 chunk
* @returns {boolean} 是否为入口模块
*/
isEntryModuleInChunk(module, chunk) {
const cgc = this._getChunkGraphChunk(chunk);
return cgc.entryModules.has(module); // 直接查表
}
/**
* 连接 chunk 与其入口模块,并指定对应的 chunkGroup(entrypoint)
* @param {Chunk} chunk 要连接的 chunk
* @param {Module} module 入口模块
* @param {Entrypoint} entrypoint 所属入口点组
*/
connectChunkAndEntryModule(chunk, module, entrypoint) {
const cgm = this._getChunkGraphModule(module);
const cgc = this._getChunkGraphChunk(chunk);
if (cgm.entryInChunks === undefined) {
cgm.entryInChunks = new Set(); // 初始化 entryInChunks
}
cgm.entryInChunks.add(chunk); // 记录该模块在哪些 chunk 作为入口
cgc.entryModules.set(module, entrypoint); // 在 chunk 中标记该模块及其所属入口组
}
/**
* 连接 chunk 与 runtime 模块
* @param {Chunk} chunk 目标 chunk
* @param {RuntimeModule} module runtime 模块
*/
connectChunkAndRuntimeModule(chunk, module) {
const cgm = this._getChunkGraphModule(module);
const cgc = this._getChunkGraphChunk(chunk);
if (cgm.runtimeInChunks === undefined) {
cgm.runtimeInChunks = new Set(); // 初始化 runtimeInChunks
}
cgm.runtimeInChunks.add(chunk); // 模块关联到 chunk
cgc.runtimeModules.add(module); // chunk 关联到模块
}
/**
* 添加需要完整 hash 的 runtime 模块
* @param {Chunk} chunk 所在 chunk
* @param {RuntimeModule} module 模块
*/
addFullHashModuleToChunk(chunk, module) {
const cgc = this._getChunkGraphChunk(chunk);
if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
cgc.fullHashModules.add(module); // 添加到 fullHashModules 集合
}
/**
* 添加仅依赖 hash 的 runtime 模块(非 full hash)
* @param {Chunk} chunk 所在 chunk
* @param {RuntimeModule} module 模块
*/
addDependentHashModuleToChunk(chunk, module) {
const cgc = this._getChunkGraphChunk(chunk);
if (cgc.dependentHashModules === undefined)
cgc.dependentHashModules = new Set();
cgc.dependentHashModules.add(module); // 添加到 dependent 集合
}
/**
* 断开 chunk 与其入口模块的关系
* @param {Chunk} chunk 要断开的 chunk
* @param {Module} module 要断开的模块
*/
disconnectChunkAndEntryModule(chunk, module) {
const cgm = this._getChunkGraphModule(module);
const cgc = this._getChunkGraphChunk(chunk);
(cgm.entryInChunks).delete(chunk); // 从模块的 entryInChunks 中移除
if ((cgm.entryInChunks).size === 0) {
cgm.entryInChunks = undefined; // 若已无引用,则置为 undefined
}
cgc.entryModules.delete(module); // 从 chunk 的 entryModules 中移除
}
/**
* 断开 chunk 与其 runtime 模块的关系
* @param {Chunk} chunk 目标 chunk
* @param {RuntimeModule} module runtime 模块
*/
disconnectChunkAndRuntimeModule(chunk, module) {
const cgm = this._getChunkGraphModule(module);
const cgc = this._getChunkGraphChunk(chunk);
(cgm.runtimeInChunks).delete(chunk); // 模块中移除 chunk 引用
if ((cgm.runtimeInChunks).size === 0) {
cgm.runtimeInChunks = undefined; // 无引用则置空
}
cgc.runtimeModules.delete(module); // chunk 中移除该模块
}