-
getChunkConditionMap(chunk, filterFn)- 遍历 chunk 所引用的所有 chunk,应用过滤函数并返回
{chunkId: 是否通过}映射。
- 遍历 chunk 所引用的所有 chunk,应用过滤函数并返回
-
hasModuleInGraph(chunk, filterFn, filterChunkFn)- 广度优先遍历 chunk 所在 chunkGroup 及其子组,查找是否存在符合模块过滤条件的模块。
-
compareChunks(chunkA, chunkB)-
用于排序比较两个 chunk:
- 模块数量多的优先;
- 如果数量相同,按模块标识符排序后比较模块顺序。
-
-
getChunkModulesSize(chunk)- 返回 chunk 中所有模块的大小总和(使用缓存获取)。
-
getChunkModulesSizes(chunk)- 返回 chunk 中所有模块按不同源类型(sourceType)分类的大小。
-
getChunkRootModules(chunk)- 返回 chunk 中的所有根模块(没有被依赖的模块),并按标识符排序。
-
getChunkSize(chunk, options)-
返回 chunk 的总估算大小,包含:
- 模块大小;
- 固定开销;
- 如果是初始 chunk,还会乘以一个倍数(默认 10 倍)。
-
-
getIntegratedChunksSize(chunkA, chunkB, options)-
返回将两个 chunk 合并后的总大小:
- 所有模块去重后求大小;
- 如果有初始 chunk,乘倍数。
-
-
canChunksBeIntegrated(chunkA, chunkB)-
判断两个 chunk 是否可以合并,合并条件包括:
- 两者都没有设置禁止合并;
- 两者 runtime 情况一致,或者其中一个可复用另一个;
- 都不是入口 chunk。
-
/**
* 获取 chunk 所引用的所有 chunk 的条件映射
* @param {Chunk} chunk - 起始 chunk
* @param {ChunkFilterPredicate} filterFn - 用于判断 chunk 是否符合条件的函数
* @returns {Record<string|number, boolean>} - 以 chunk id 为键、是否符合条件为值的映射对象
*/
getChunkConditionMap(chunk, filterFn) {
const map = Object.create(null); // 创建一个无原型的纯净对象作为映射容器
for (const c of chunk.getAllReferencedChunks()) { // 遍历 chunk 所有引用的 chunk(包括自身和间接引用)
map[/** @type {ChunkId} */ (c.id)] = filterFn(c, this); // 对每个 chunk 执行过滤函数,结果存入映射表中
}
return map; // 返回构建的映射对象
}
/**
* 判断是否在 chunk 所属的 chunk graph 中存在符合条件的模块
* @param {Chunk} chunk - 起始 chunk
* @param {ModuleFilterPredicate} filterFn - 模块筛选函数
* @param {ChunkFilterPredicate=} filterChunkFn - 可选,chunk 筛选函数
* @returns {boolean} - 如果图中存在符合条件的模块,则返回 true
*/
hasModuleInGraph(chunk, filterFn, filterChunkFn) {
const queue = new Set(chunk.groupsIterable); // 初始化遍历队列,包含 chunk 所属的所有 chunkGroup
const chunksProcessed = new Set(); // 用于记录已经处理过的 chunk,避免重复
for (const chunkGroup of queue) { // 遍历 chunkGroup 队列
for (const innerChunk of chunkGroup.chunks) { // 遍历每个 chunkGroup 中的 chunk
if (!chunksProcessed.has(innerChunk)) { // 若该 chunk 未处理过
chunksProcessed.add(innerChunk); // 标记为已处理
if (!filterChunkFn || filterChunkFn(innerChunk, this)) { // 如果没有过滤函数或 chunk 通过过滤
for (const module of this.getChunkModulesIterable(innerChunk)) { // 遍历该 chunk 中所有模块
if (filterFn(module)) { // 若模块符合条件
return true; // 返回 true,表示存在该模块
}
}
}
}
}
for (const child of chunkGroup.childrenIterable) { // 将 chunkGroup 的子 group 加入队列递归处理
queue.add(child);
}
}
return false; // 遍历完成未找到符合条件模块,返回 false
}
/**
* 比较两个 chunk 的模块数量与内容,用于排序
* @param {Chunk} chunkA - 第一个 chunk
* @param {Chunk} chunkB - 第二个 chunk
* @returns {-1|0|1} - 排序值:chunkA 应排在前返回 -1,排在后返回 1,相等返回 0
*/
compareChunks(chunkA, chunkB) {
const cgcA = this._getChunkGraphChunk(chunkA); // 获取 chunkA 的内部图数据
const cgcB = this._getChunkGraphChunk(chunkB); // 获取 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); // 逐项比较模块顺序决定优先级
}
/**
* 获取 chunk 所有模块的总大小
* @param {Chunk} chunk - 目标 chunk
* @returns {number} - 模块大小总和
*/
getChunkModulesSize(chunk) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 chunk 的图结构数据
return cgc.modules.getFromUnorderedCache(getModulesSize); // 使用缓存获取模块总大小(避免重复计算)
}
/**
* 获取 chunk 中所有模块按 sourceType 分类后的大小
* @param {Chunk} chunk - 目标 chunk
* @returns {Record<string, number>} - 各 sourceType 的大小映射
*/
getChunkModulesSizes(chunk) {
const cgc = this._getChunkGraphChunk(chunk); // 获取图数据
return cgc.modules.getFromUnorderedCache(getModulesSizes); // 从缓存中获取每个源类型的模块大小
}
/**
* 获取 chunk 中的根模块(没有任何入边依赖的模块)
* @param {Chunk} chunk - 目标 chunk
* @returns {Module[]} - 按标识符排序的根模块数组
*/
getChunkRootModules(chunk) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 chunk 的图结构
return cgc.modules.getFromUnorderedCache(this._getGraphRoots); // 使用缓存和内部方法获取根模块列表
}
/**
* 获取 chunk 的综合大小(模块大小 + 开销 + 条件倍增因子)
* @param {Chunk} chunk - 目标 chunk
* @param {ChunkSizeOptions} options - 配置选项,包含开销和乘数
* @returns {number} - chunk 的估算大小
*/
getChunkSize(chunk, options = {}) {
const cgc = this._getChunkGraphChunk(chunk); // 获取 chunk 图数据
const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize); // 获取模块总大小
const chunkOverhead =
typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000; // chunk 本身的开销,默认 10000
const entryChunkMultiplicator =
typeof options.entryChunkMultiplicator === "number"
? options.entryChunkMultiplicator
: 10; // 初始 chunk 的大小乘数,默认 10
return (
chunkOverhead +
modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1) // 如果 chunk 是初始 chunk,则乘以乘数
);
}
/**
* 获取两个 chunk 合并后的总大小
* @param {Chunk} chunkA - 第一个 chunk
* @param {Chunk} chunkB - 第二个 chunk
* @param {ChunkSizeOptions} options - 配置项(开销、乘数)
* @returns {number} - 合并后总大小
*/
getIntegratedChunksSize(chunkA, chunkB, options = {}) {
const cgcA = this._getChunkGraphChunk(chunkA); // 获取 chunkA 图数据
const cgcB = this._getChunkGraphChunk(chunkB); // 获取 chunkB 图数据
const allModules = new Set(cgcA.modules); // 创建 Set 保存合并模块
for (const m of cgcB.modules) allModules.add(m); // 添加 chunkB 的模块到合并集合中
const 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)
); // 如果任一 chunk 是初始 chunk,则大小乘倍数
}
/**
* 判断两个 chunk 是否可以被合并
* @param {Chunk} chunkA - 第一个 chunk
* @param {Chunk} chunkB - 第二个 chunk
* @returns {boolean} - 返回 true 表示可以合并
*/
canChunksBeIntegrated(chunkA, chunkB) {
if (chunkA.preventIntegration || chunkB.preventIntegration) {
// 显式禁止合并的 chunk 不允许整合
return false;
}
const hasRuntimeA = chunkA.hasRuntime(); // 是否拥有 runtime
const hasRuntimeB = chunkB.hasRuntime();
if (hasRuntimeA !== hasRuntimeB) {
// 如果 runtime 存在不一致,只有 runtime 可被另一个复用时才能合并
if (hasRuntimeA) {
return isAvailableChunk(chunkA, chunkB);
} else if (hasRuntimeB) {
return isAvailableChunk(chunkB, chunkA);
}
return false;
}
if (
this.getNumberOfEntryModules(chunkA) > 0 ||
this.getNumberOfEntryModules(chunkB) > 0
) {
// 若任意一个 chunk 是入口 chunk,则不允许合并
return false;
}
return true; // 上述条件都满足,允许合并
}