webpack 模块图 第 三 节

🔁 模块连接管理

  • copyOutgoingModuleConnections(oldModule, newModule, filterConnection)

    • 作用:将旧模块的所有出站连接(即它依赖的模块)复制到新模块中。

    • 使用场景:模块替换(如 HMR)、模块克隆等。

    • 关键点

      • 如果 oldModule === newModule,不做处理。
      • 支持使用 filterConnection 过滤要复制的连接。
      • 会克隆 ModuleGraphConnection 对象并重新设定 originModule
      • 同时会更新目标模块的入站连接集合。
  • getConnection(dependency)

    • 作用 :获取某个依赖对象对应的连接(ModuleGraphConnection)。

    • 细节

      • 优先查 _dependencyMap 缓存。
      • 若未命中,则尝试从依赖所属模块的 _unassignedConnections 中恢复连接。
      • 最终会缓存结果,无连接则缓存为 null
  • getResolvedModule(dependency)

    • 作用 :获取某依赖最终解析出的模块(resolvedModule)。
    • 依赖于getConnection()
  • getModule(dependency)

    • 作用 :获取依赖指向的目标模块(connection.module)。
    • 依赖于getConnection()
  • getOrigin(dependency)

    • 作用 :获取发出该依赖的源模块(connection.originModule)。
  • getResolvedOrigin(dependency)

    • 作用 :获取依赖解析后的源模块(resolvedOriginModule)。
  • getIncomingConnections(module)

    • 作用:返回所有指向该模块的连接(谁引用了它)。
    • 结果类型Iterable<ModuleGraphConnection>
  • getOutgoingConnections(module)

    • 作用:获取模块出站连接(它引用了谁)。
    • 结果类型Iterable<ModuleGraphConnection>
    • 若未定义,返回空集合 EMPTY_SET
  • getIncomingConnectionsByOriginModule(module)

    • 作用:将模块的入站连接按"来源模块"分组。
    • 缓存结构Map<Module | undefined | null, ModuleGraphConnection[]>
  • getOutgoingConnectionsByModule(module)

    • 作用:将模块的出站连接按"目标模块"分组。
    • 缓存结构Map<Module | undefined, ModuleGraphConnection[]>

🧩 模块元信息管理

  • addExtraReason(module, explanation)

    • 作用:给模块添加一个"虚拟连接"作为额外引用理由(例如:它是某种默认模块)。
    • 效果 :创建一个 ModuleGraphConnection(null, null, module, explanation) 加入入站集合。
  • getProfile(module)

    • 作用 :获取模块的性能分析信息(ModuleProfile)。
    • 用途:用于分析构建时长、缓存情况等。
  • setProfile(module, profile)

    • 作用:设置模块的性能分析信息。
  • getIssuer(module)

    • 作用:获取模块的"issuer",即最初将其引入的模块。
    • 用途:用于确定模块链路、生成模块名等。
  • setIssuer(module, issuer)

    • 作用:设置模块的 issuer。
  • setIssuerIfUnset(module, issuer)

    • 作用:仅在尚未设置 issuer 时设置它,避免重复赋值。
  • getOptimizationBailout(module)

    • 作用:获取模块的优化阻止信息。
    • 返回值 :可能是 true、字符串数组,解释为何模块未被优化。
  • getProvidedExports(module)

    • 作用:获取模块提供的导出信息(比如哪些命名导出可用于 Tree-shaking)。
    • 调用的是内部的 exports.getProvidedExports() 方法。
js 复制代码
/**
 * 拷贝旧模块的所有出站连接到新模块(可通过 filter 过滤)
 * @param {Module} oldModule 原始模块
 * @param {Module} newModule 新模块
 * @param {function(ModuleGraphConnection): boolean} filterConnection 过滤函数,返回 true 表示需要拷贝
 * @returns {void}
 */
copyOutgoingModuleConnections(oldModule, newModule, filterConnection) {
	if (oldModule === newModule) return;
	const oldMgm = this._getModuleGraphModule(oldModule);
	const newMgm = this._getModuleGraphModule(newModule);

	// 获取旧模块的出站连接
	const oldConnections = oldMgm.outgoingConnections;
	if (oldConnections !== undefined) {
		// 初始化新模块的出站连接集合
		if (newMgm.outgoingConnections === undefined) {
			newMgm.outgoingConnections = new SortableSet();
		}
		const newConnections = newMgm.outgoingConnections;

		// 遍历旧的连接,如果满足过滤条件则复制到新模块中
		for (const connection of oldConnections) {
			if (filterConnection(connection)) {
				const newConnection = connection.clone(); // 克隆连接对象
				newConnection.originModule = newModule; // 设置新的起源模块
				newConnections.add(newConnection); // 添加到新模块的出站连接中

				// 同时更新目标模块的入站连接
				if (newConnection.module !== undefined) {
					const otherMgm = this._getModuleGraphModule(newConnection.module);
					otherMgm.incomingConnections.add(newConnection);
				}
			}
		}
	}
}

/**
 * 为模块添加一个额外引用理由(解释为何该模块被包含)
 * @param {Module} module 被引用的模块
 * @param {string} explanation 解释文本
 * @returns {void}
 */
addExtraReason(module, explanation) {
	const connections = this._getModuleGraphModule(module).incomingConnections;
	connections.add(new ModuleGraphConnection(null, null, module, explanation));
}

/**
 * 获取某依赖所解析到的最终模块
 * @param {Dependency} dependency 依赖对象
 * @returns {Module | null} 解析出的模块,若无结果返回 null
 */
getResolvedModule(dependency) {
	const connection = this.getConnection(dependency);
	return connection !== undefined ? connection.resolvedModule : null;
}

/**
 * 获取依赖对应的连接信息
 * @param {Dependency} dependency 依赖对象
 * @returns {ModuleGraphConnection | undefined} 返回连接对象或 undefined
 */
getConnection(dependency) {
	const connection = this._dependencyMap.get(dependency);
	if (connection === undefined) {
		// 尝试从所属模块中查找未分配的连接
		const module = this.getParentModule(dependency);
		if (module !== undefined) {
			const mgm = this._getModuleGraphModule(module);
			if (mgm._unassignedConnections && mgm._unassignedConnections.length !== 0) {
				let foundConnection;
				for (const connection of mgm._unassignedConnections) {
					this._dependencyMap.set(connection.dependency, connection);
					if (connection.dependency === dependency)
						foundConnection = connection;
				}
				mgm._unassignedConnections.length = 0;
				if (foundConnection !== undefined) {
					return foundConnection;
				}
			}
		}
		this._dependencyMap.set(dependency, null);
		return;
	}
	return connection === null ? undefined : connection;
}

/**
 * 获取某依赖所指向的目标模块(未解析)
 * @param {Dependency} dependency 依赖对象
 * @returns {Module | null} 模块对象或 null
 */
getModule(dependency) {
	const connection = this.getConnection(dependency);
	return connection !== undefined ? connection.module : null;
}

/**
 * 获取依赖的来源模块
 * @param {Dependency} dependency 依赖对象
 * @returns {Module | null} 来源模块
 */
getOrigin(dependency) {
	const connection = this.getConnection(dependency);
	return connection !== undefined ? connection.originModule : null;
}

/**
 * 获取依赖的"解析后"的来源模块
 * @param {Dependency} dependency 依赖对象
 * @returns {Module | null} 解析后的来源模块
 */
getResolvedOrigin(dependency) {
	const connection = this.getConnection(dependency);
	return connection !== undefined ? connection.resolvedOriginModule : null;
}

/**
 * 获取指定模块的所有入站连接(被哪些模块引用)
 * @param {Module} module 目标模块
 * @returns {Iterable<ModuleGraphConnection>} 入站连接集合
 */
getIncomingConnections(module) {
	const connections = this._getModuleGraphModule(module).incomingConnections;
	return connections;
}

/**
 * 获取指定模块的所有出站连接(引用了哪些模块)
 * @param {Module} module 模块对象
 * @returns {Iterable<ModuleGraphConnection>} 出站连接集合
 */
getOutgoingConnections(module) {
	const connections = this._getModuleGraphModule(module).outgoingConnections;
	return connections === undefined ? EMPTY_SET : connections;
}

/**
 * 获取模块的所有入站连接,并按来源模块分组(用于分析引用来源)
 * @param {Module} module 模块对象
 * @returns {readonly Map<Module | undefined | null, readonly ModuleGraphConnection[]>} 分组后的入站连接
 */
getIncomingConnectionsByOriginModule(module) {
	const connections = this._getModuleGraphModule(module).incomingConnections;
	return connections.getFromUnorderedCache(getConnectionsByOriginModule);
}

/**
 * 获取模块的出站连接,并按目标模块分组
 * @param {Module} module 模块对象
 * @returns {readonly Map<Module | undefined, readonly ModuleGraphConnection[]> | undefined} 分组后的出站连接
 */
getOutgoingConnectionsByModule(module) {
	const connections = this._getModuleGraphModule(module).outgoingConnections;
	return connections === undefined
		? undefined
		: connections.getFromUnorderedCache(getConnectionsByModule);
}

/**
 * 获取模块的性能分析信息(构建时间等)
 * @param {Module} module 模块对象
 * @returns {ModuleProfile | undefined} 模块性能数据
 */
getProfile(module) {
	const mgm = this._getModuleGraphModule(module);
	return mgm.profile;
}

/**
 * 设置模块的性能分析信息
 * @param {Module} module 模块对象
 * @param {ModuleProfile | undefined} profile 要设置的性能信息
 * @returns {void}
 */
setProfile(module, profile) {
	const mgm = this._getModuleGraphModule(module);
	mgm.profile = profile;
}

/**
 * 获取模块的"issuer"(最初引入它的模块)
 * @param {Module} module 模块对象
 * @returns {Module | null | undefined} issuer 模块
 */
getIssuer(module) {
	const mgm = this._getModuleGraphModule(module);
	return mgm.issuer;
}

/**
 * 设置模块的 issuer(谁引入了该模块)
 * @param {Module} module 模块对象
 * @param {Module | null} issuer 引入该模块的模块
 * @returns {void}
 */
setIssuer(module, issuer) {
	const mgm = this._getModuleGraphModule(module);
	mgm.issuer = issuer;
}

/**
 * 如果尚未设置 issuer,则设置一个
 * @param {Module} module 模块对象
 * @param {Module | null} issuer 引入该模块的模块
 * @returns {void}
 */
setIssuerIfUnset(module, issuer) {
	const mgm = this._getModuleGraphModule(module);
	if (mgm.issuer === undefined) mgm.issuer = issuer;
}

/**
 * 获取模块的优化提示信息(比如为何未优化)
 * @param {Module} module 模块对象
 * @returns {(string | OptimizationBailoutFunction)[]} 优化提示信息数组
 */
getOptimizationBailout(module) {
	const mgm = this._getModuleGraphModule(module);
	return mgm.optimizationBailout;
}

/**
 * 获取模块的导出信息(用于 Tree-shaking)
 * @param {Module} module 模块对象
 * @returns {true | string[] | null} 提供的导出名称或 null / true
 */
getProvidedExports(module) {
	const mgm = this._getModuleGraphModule(module);
	return mgm.exports.getProvidedExports();
}
相关推荐
打小就很皮...2 小时前
简单实现Ajax基础应用
前端·javascript·ajax
wanhengidc3 小时前
服务器租用:高防CDN和加速CDN的区别
运维·服务器·前端
哆啦刘小洋4 小时前
HTML Day04
前端·html
再学一点就睡4 小时前
JSON Schema:禁锢的枷锁还是突破的阶梯?
前端·json
从零开始学习人工智能6 小时前
FastMCP:构建 MCP 服务器和客户端的高效 Python 框架
服务器·前端·网络
烛阴6 小时前
自动化测试、前后端mock数据量产利器:Chance.js深度教程
前端·javascript·后端
好好学习O(∩_∩)O6 小时前
QT6引入QMediaPlaylist类
前端·c++·ffmpeg·前端框架
敲代码的小吉米6 小时前
前端HTML contenteditable 属性使用指南
前端·html
testleaf6 小时前
React知识点梳理
前端·react.js·typescript
站在风口的猪11086 小时前
《前端面试题:HTML5、CSS3、ES6新特性》
前端·css3·html5