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;
	}
}
相关推荐
GISer_Jing19 分钟前
[总结篇]个人网站
前端·javascript
疯狂的沙粒40 分钟前
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
前端·uni-app·html
小妖66644 分钟前
html 滚动条滚动过快会留下边框线
前端·html
heroboyluck1 小时前
Svelte 核心语法详解:Vue/React 开发者如何快速上手?
前端·svelte
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
琹箐1 小时前
ant-design4.xx实现数字输入框; 某些输入法数字需要连续输入两次才显示
前端·javascript·anti-design-vue
程序员-小李1 小时前
VuePress完美整合Toast消息提示
前端·javascript·vue.js
Uyker2 小时前
从零开始制作小程序简单概述
前端·微信小程序·小程序
EndingCoder6 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客7 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏