✅ 类型定义与常量
-
定义了多个模块类型、结构、函数签名等,用于 JSDoc 提示。
-
常量:
EMPTY_SET
:空集合,常用于默认值。ZERO_BIG_INT
:BigInt 形式的 0。compareModuleIterables
:模块排序器。
✅ 类型别名定义
ChunkFilterPredicate
:用于过滤 chunk 的函数类型。ModuleFilterPredicate
:用于过滤 module 的函数类型。EntryModuleWithChunkGroup
:模块和它对应入口的元组。ChunkSizeOptions
:chunk 体积计算参数。
✅ 工具类
-
ModuleHashInfo
:- 存储模块的 hash 和渲染后的 hash。
- 用于构建缓存和是否重新编译判断。
✅ 工具函数
-
getArray(set)
:将SortableSet
转换为普通数组。 -
getModuleRuntimes(chunks)
:获取 chunk 集合中的所有 runtime。 -
modulesBySourceType(sourceTypesByModule)
:- 把模块集合按 sourceType 分类。
- 可重用原集合,优化排序缓存。
-
createOrderedArrayFunction(comparator)
:- 创建一个集合转排序数组的函数,并做缓存。
-
getModulesSize(modules)
:计算所有模块的总大小(所有类型总和)。 -
getModulesSizes(modules)
:按 sourceType 分类统计每类大小。 -
isAvailableChunk(a, b)
:- 判断 chunk
a
是否一定是 chunkb
的父 chunk。 - 用于 chunk 之间的依赖关系判断。
- 判断 chunk
✅ ChunkGraphModule 类
chunks
:模块所属的 chunk 集合。entryInChunks
:如果模块是入口模块,则保存相关 chunk。runtimeInChunks
:如果模块是 runtime 模块,则保存相关 chunk。hashes
:不同 runtime 下的模块 hash 信息。id
:模块的输出 ID。runtimeRequirements
:各 runtime 下的 runtime 依赖。graphHashes
:模块图结构的 hash。graphHashesWithConnections
:模块图+依赖连接信息的 hash(更严格)。
js
// ==== 类型导入(用于 JSDoc 类型提示) ====
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Chunk").ChunkId} ChunkId */
/** @typedef {import("./ChunkGroup")} ChunkGroup */
/** @typedef {import("./Generator").SourceTypes} SourceTypes */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./ModuleGraphConnection").ConnectionState} ConnectionState */
/** @typedef {import("./RuntimeModule")} RuntimeModule */
/** @typedef {typeof import("./util/Hash")} Hash */
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
// ==== 常量定义 ====
/** 空集合常量(不可变),可用于默认值等 */
const EMPTY_SET = new Set();
/** 零值的 BigInt 常量 */
const ZERO_BIG_INT = BigInt(0);
/** 比较模块集合的工具函数,用于排序 */
const compareModuleIterables = compareIterables(compareModulesByIdentifier);
// ==== 类型别名定义 ====
/**
* 过滤 chunk 的函数类型定义
* @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate
*/
/**
* 过滤模块的函数类型定义
* @typedef {(m: Module) => boolean} ModuleFilterPredicate
*/
/**
* 模块和它所属的入口 chunk group 对(可能 undefined)
* @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup
*/
/**
* 表示计算 chunk 大小时的一些配置参数
* @typedef {object} ChunkSizeOptions
* @property {number=} chunkOverhead chunk 的固定开销
* @property {number=} entryChunkMultiplicator 入口 chunk 的权重乘数
*/
// ==== 工具类 ====
/**
* 模块的 hash 信息,用于缓存和优化重构
*/
class ModuleHashInfo {
/**
* @param {string} hash 模块构建产物的 hash
* @param {string} renderedHash 渲染后的 hash,用于输出文件名等
*/
constructor(hash, renderedHash) {
this.hash = hash;
this.renderedHash = renderedHash;
}
}
// ==== 工具函数 ====
/**
* 将 SortableSet 转为数组
* @template T
* @param {SortableSet<T>} set 可排序的集合
* @returns {T[]} 转换后的数组
*/
const getArray = set => Array.from(set);
/**
* 获取某些 chunk 所涉及的 runtime 集合(RuntimeSpecSet)
* @param {SortableSet<Chunk>} chunks chunk 集合
* @returns {RuntimeSpecSet} 所有 runtime 的集合
*/
const getModuleRuntimes = chunks => {
const runtimes = new RuntimeSpecSet();
for (const chunk of chunks) {
runtimes.add(chunk.runtime);
}
return runtimes;
};
/**
* 把模块集合根据 sourceType 分类
* @param {WeakMap<Module, Set<string>> | undefined} sourceTypesByModule 提前缓存的模块 sourceType
* @returns {function (SortableSet<Module>): Map<string, SortableSet<Module>>} 分类后的模块映射表
*/
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) {
// 如果所有模块都包含该 sourceType,就直接复用原集合,提高排序缓存效率
if (innerSet.size === set.size) {
map.set(key, set);
}
}
return map;
};
// 默认情况下不提供预缓存,直接调用模块的 getSourceTypes 方法
const defaultModulesBySourceType = modulesBySourceType(undefined);
/**
* 创建一个能排序集合并转数组的函数,并缓存该函数避免重复生成
* @template T
* @type {WeakMap<Function, any>}
*/
const createOrderedArrayFunctionMap = new WeakMap();
/**
* 返回一个函数,该函数能将集合排序后转成数组
* @template T
* @param {function(T, T): -1|0|1} comparator 排序比较器
* @returns {SetToArrayFunction<T>} 生成的转换函数
*/
const createOrderedArrayFunction = comparator => {
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;
};
/**
* 计算模块总大小(所有 sourceType 加起来)
* @param {Iterable<Module>} modules 模块集合
* @returns {number} 模块总大小
*/
const getModulesSize = modules => {
let size = 0;
for (const module of modules) {
for (const type of module.getSourceTypes()) {
size += module.size(type);
}
}
return size;
};
/**
* 分 sourceType 统计模块大小
* @param {Iterable<Module>} modules 模块集合
* @returns {Record<string, number>} 每种类型的大小
*/
const getModulesSizes = modules => {
const 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;
};
/**
* 判断 chunk `a` 是否是 chunk `b` 的父 chunk
* @param {Chunk} a 父 chunk
* @param {Chunk} b 子 chunk
* @returns {boolean} 如果 a 是 b 的父 chunk,返回 true
*/
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;
};
// ==== 类型别名:用于 ChunkGraphModule 中属性类型标注 ====
/** @typedef {Set<Chunk>} EntryInChunks */
/** @typedef {Set<Chunk>} RuntimeInChunks */
/** @typedef {string | number} ModuleId */
// ==== ChunkGraph 中用于存储模块信息的结构 ====
class ChunkGraphModule {
constructor() {
/** @type {SortableSet<Chunk>} 模块所属的 chunk 集合 */
this.chunks = new SortableSet();
/** @type {EntryInChunks | undefined} 如果模块是 entry 模块,这里存放其所在的入口 chunk 集合 */
this.entryInChunks = undefined;
/** @type {RuntimeInChunks | undefined} 如果模块是 runtime 模块,这里存放其对应 chunk */
this.runtimeInChunks = undefined;
/** @type {RuntimeSpecMap<ModuleHashInfo> | undefined} 各 runtime 对应的 hash 信息 */
this.hashes = undefined;
/** @type {ModuleId | null} 模块 ID(用于输出) */
this.id = null;
/** @type {RuntimeSpecMap<Set<string>> | undefined} 各 runtime 所依赖的 runtime helper */
this.runtimeRequirements = undefined;
/** @type {RuntimeSpecMap<string> | undefined} 模块图结构的 hash */
this.graphHashes = undefined;
/** @type {RuntimeSpecMap<string> | undefined} 模块图 + 连接信息 的 hash(用于更精确地判断是否变化) */
this.graphHashesWithConnections = undefined;
}
}