webpack 模块图 第 一 节

这段代码是 Webpack 模块图构建系统 的重要组成部分,ModuleGraphModule 是每个模块在图中的状态容器,而两个工具函数是为了高效分类模块之间的连接关系,为优化(如 Tree Shaking)和构建性能分析打基础。

ModuleGraphModule 类主要属性说明

  • incomingConnections

    • 类型:SortableSet<ModuleGraphConnection>
    • 说明:当前模块的入边连接(谁依赖了我)
  • outgoingConnections

    • 类型:SortableSet<ModuleGraphConnection> | undefined
    • 说明:当前模块的出边连接(我依赖了谁)
  • issuer

    • 类型:Module | null | undefined
    • 说明:引入该模块的模块(谁把我 import 了)
  • optimizationBailout

    • 类型:(string | OptimizationBailoutFunction)[]
    • 说明:记录该模块未被优化的原因(如 Tree Shaking 无效)
  • exports

    • 类型:ExportsInfo
    • 说明:模块导出信息(支持 Tree Shaking 和导出分析)
  • preOrderIndex

    • 类型:number | null
    • 说明:图遍历时的前序编号(DFS 顺序)
  • postOrderIndex

    • 类型:number | null
    • 说明:图遍历时的后序编号(DFS 结束时标号)
  • depth

    • 类型:number | null
    • 说明:模块在依赖图中的深度(用于排序优化)
  • profile

    • 类型:ModuleProfile | undefined
    • 说明:构建模块时的性能分析信息
  • async

    • 类型:boolean
    • 说明:是否是异步模块(如 import() 引入)
  • _unassignedConnections

    • 类型:ModuleGraphConnection[] | undefined
    • 说明:尚未归类的连接(构建过程中使用)

工具函数说明

  • getConnectionsByOriginModule(set)

    • 输入参数:SortableSet<ModuleGraphConnection>
    • 返回值:Map<Module | undefined, ModuleGraphConnection[]>
    • 说明:按照连接的 originModule(来源模块)对连接集合进行分组
  • getConnectionsByModule(set)

    • 输入参数:SortableSet<ModuleGraphConnection>
    • 返回值:Map<Module | undefined, ModuleGraphConnection[]>
    • 说明:按照连接的 module(目标模块)对连接集合进行分组

    类型别名说明

  • IncomingConnections

    • 实际类型:SortableSet<ModuleGraphConnection>
    • 说明:模块的所有入连接集合(被谁依赖)
  • OutgoingConnections

    • 实际类型:SortableSet<ModuleGraphConnection>
    • 说明:模块的所有出连接集合(依赖了谁)
  • OptimizationBailoutFunction

    • 类型定义:一个返回字符串的函数,接收 RequestShortener
    • 说明:用于说明模块为什么无法优化(比如缺少静态依赖信息)
js 复制代码
/** 引入类型定义,用于类型提示(非实际导入,只用于注释) */
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleProfile")} ModuleProfile */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */

/**
 * 优化失败回调类型定义。
 * 返回一个字符串,用于提示为什么该模块未被优化。
 * 可用于 `optimizationBailout` 数组中的元素。
 *
 * @callback OptimizationBailoutFunction
 * @param {RequestShortener} requestShortener - 用于路径简化
 * @returns {string} 优化失败原因
 */

const EMPTY_SET = new Set(); // 空集合常量,可复用避免重复创建

/**
 * 工具函数:按连接的"来源模块"(originModule)将连接进行分组
 * 
 * @param {SortableSet<ModuleGraphConnection>} set - 输入的模块连接集合
 * @returns {readonly Map<Module | undefined, readonly ModuleGraphConnection[]>}
 *          返回以"来源模块"为 key、连接数组为 value 的 Map
 */
const getConnectionsByOriginModule = set => {
	const map = new Map();
	let lastModule = 0; // 缓存上一个处理的模块
	let lastList;

	for (const connection of set) {
		const { originModule } = connection;

		// 如果与上一个模块相同,直接向缓存的连接数组中添加
		if (lastModule === originModule) {
			(lastList).push(connection);
		} else {
			lastModule = originModule;
			const list = map.get(originModule);

			if (list !== undefined) {
				lastList = list;
				list.push(connection);
			} else {
				const list = [connection];
				lastList = list;
				map.set(originModule, list);
			}
		}
	}
	return map;
};

/**
 * 工具函数:按连接的"目标模块"(module)将连接进行分组
 * 
 * @param {SortableSet<ModuleGraphConnection>} set - 输入的模块连接集合
 * @returns {readonly Map<Module | undefined, readonly ModuleGraphConnection[]>}
 *          返回以"目标模块"为 key、连接数组为 value 的 Map
 */
const getConnectionsByModule = set => {
	const map = new Map();
	let lastModule = 0;
	let lastList;

	for (const connection of set) {
		const { module } = connection;

		if (lastModule === module) {
			(lastList).push(connection);
		} else {
			lastModule = module;
			const list = map.get(module);

			if (list !== undefined) {
				lastList = list;
				list.push(connection);
			} else {
				const list = [connection];
				lastList = list;
				map.set(module, list);
			}
		}
	}
	return map;
};

/** 类型别名:模块图中"指向该模块的连接" */
 /** @typedef {SortableSet<ModuleGraphConnection>} IncomingConnections */

/** 类型别名:模块图中"从该模块出发的连接" */
 /** @typedef {SortableSet<ModuleGraphConnection>} OutgoingConnections */

/**
 * 表示模块图中某个模块的元信息(状态、连接、导出等)
 */
class ModuleGraphModule {
	constructor() {
		/** @type {IncomingConnections} 当前模块的入边连接(谁依赖我) */
		this.incomingConnections = new SortableSet();

		/** @type {OutgoingConnections | undefined} 当前模块的出边连接(我依赖谁) */
		this.outgoingConnections = undefined;

		/** @type {Module | null | undefined} 引入该模块的模块(issuer) */
		this.issuer = undefined;

		/** @type {(string | OptimizationBailoutFunction)[]} 记录为什么该模块无法被优化 */
		this.optimizationBailout = [];

		/** @type {ExportsInfo} 当前模块的导出信息(用于 Tree Shaking 等优化) */
		this.exports = new ExportsInfo();

		/** @type {number | null} 当前模块在图遍历中的"前序遍历索引" */
		this.preOrderIndex = null;

		/** @type {number | null} 当前模块在图遍历中的"后序遍历索引" */
		this.postOrderIndex = null;

		/** @type {number | null} 模块在依赖图中的深度(越深优先级越低) */
		this.depth = null;

		/** @type {ModuleProfile | undefined} 构建该模块时的性能分析数据 */
		this.profile = undefined;

		/** @type {boolean} 是否为异步模块(通过 import() 等方式引入) */
		this.async = false;

		/** @type {ModuleGraphConnection[] | undefined} 未分类连接(临时存储) */
		this._unassignedConnections = undefined;
	}
}
相关推荐
brzhang5 分钟前
A2UI:但 Google 把它写成协议后,模型和交互的最后一公里被彻底补全
前端·后端·架构
coderHing[专注前端]14 分钟前
告别 try/catch 地狱:用三元组重新定义 JavaScript 错误处理
开发语言·前端·javascript·react.js·前端框架·ecmascript
UIUV31 分钟前
JavaScript中this指向机制与异步回调解决方案详解
前端·javascript·代码规范
momo10031 分钟前
IndexedDB 实战:封装一个通用工具类,搞定所有本地存储需求
前端·javascript
liuniansilence31 分钟前
🚀 高并发场景下的救星:BullMQ如何实现智能流量削峰填谷
前端·分布式·消息队列
再花31 分钟前
在Angular中实现基于nz-calendar的日历甘特图
前端·angular.js
GISer_Jing43 分钟前
今天看了京东零售JDS的保温直播,秋招,好像真的结束了,接下来就是论文+工作了!!!加油干论文,学&分享技术
前端·零售
Mapmost1 小时前
【高斯泼溅】如何将“歪头”的3DGS模型精准“钉”在地图上,杜绝后续误差?
前端
废春啊1 小时前
前端工程化
运维·服务器·前端
爱上妖精的尾巴1 小时前
6-9 WPS JS宏Map、 set、get、delete、clear()映射的添加、修改、删除
前端·wps·js宏·jsa