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();
}
相关推荐
打野赵怀真6 分钟前
React Hooks 的优势和使用场景
前端·javascript
HaushoLin10 分钟前
ERR_PNPM_DLX_NO_BIN No binaries found in tailwindcss
前端·vue.js·css3·html5
Lafar11 分钟前
Widget 树和 Element 树和RenderObject树是一一 对应的吗
前端
小桥风满袖12 分钟前
炸裂,前端神级动效库合集
前端·css
匆叔13 分钟前
Tauri 桌面端开发
前端·vue.js
1_2_3_14 分钟前
react-antd-column-resize(让你的table列可以拖拽列宽)
前端
Lafar14 分钟前
Flutter和iOS混合开发
前端·面试
九龙湖兔兔14 分钟前
pnpm给插件(naiveUI)打补丁
前端·架构
知心宝贝15 分钟前
【Nest.js 通关秘籍 - 基础篇】带你轻松掌握后端开发
前端·javascript·架构