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();
}
相关推荐
梦曦i3 分钟前
v0.2.0 架构升级:class + reactive 重塑状态管理
前端·uni-app x
布丁爱干饭4 分钟前
寄给午后
前端
java1234_小锋31 分钟前
【技术专题】CSS3 网页技术 - CSS3 布局进阶
前端·css·css3
zhippt_10141 小时前
只剩截图没有源文件?图转PPT把图片还原成可编辑幻灯片
前端·人工智能·powerpoint
shmily麻瓜小菜鸡1 小时前
TypeScript 知识点补充(第三部分:工程化与高级类型)
前端·javascript·typescript
10岁的博客2 小时前
Chrome 扩展安全攻防实录:从权限模型到真实漏洞复盘
前端·chrome·安全
QianhangQianping2 小时前
WebSocket实时推送+ HTTP 定时轮询:一块大屏两套取数怎么不打架
前端·websocket·网络协议·http·低代码·架构·数据可视化
Eider19982 小时前
Python基础知识之并发相关-2
开发语言·前端·python
用户69371750013842 小时前
AI 能写代码,但工程架构还是应该由人来定
前端·后端
Hilaku2 小时前
前端的技术判断力是怎么练出来的?
前端·javascript·程序员