webpack 核心编译器 第四节

这一节中主要介绍了模块依赖的处理,其中有对模块队列中添加模块,有和理依赖间关系的函数,对模块进行排序的函数,从软缓存中恢复模块的函数以及添模块添加到模块图的一些方法

js 复制代码
	/**
	 * 处理模块的依赖关系,将模块添加到 `processDependenciesQueue` 队列中等待处理
	 * @param {Module} module - 需要处理依赖的模块
	 * @param {ModuleCallback} callback - 处理完成后调用的回调函数
	 * @returns {void}
	 */
	processModuleDependencies(module, callback) {
		this.processDependenciesQueue.add(module, callback);
	}

	/**
	 * 以非递归方式处理模块的依赖关系,遍历 `module` 及其 `DependenciesBlock`,并设置 `moduleGraph` 依赖关系
	 * @param {Module} module - 需要处理依赖的模块
	 * @returns {void}
	 */
	processModuleDependenciesNonRecursive(module) {
		/**
		 * 递归遍历 `DependenciesBlock`,设置依赖关系
		 * @param {DependenciesBlock} block - 依赖块
		 */
		const processDependenciesBlock = block => {
			if (block.dependencies) {
				let i = 0;
				for (const dep of block.dependencies) {
					this.moduleGraph.setParents(dep, block, module, i++);
				}
			}
			if (block.blocks) {
				for (const b of block.blocks) processDependenciesBlock(b);
			}
		};

		processDependenciesBlock(module);
	}

	/**
	 * 处理模块的依赖,解析、分类并排序后,进行模块创建
	 * @param {Module} module - 需要处理的模块
	 * @param {ModuleCallback} callback - 处理完成后调用的回调函数
	 * @returns {void}
	 */
	_processModuleDependencies(module, callback) {
		/** 存储已分类和排序的依赖项 */
		const sortedDependencies = [];

		/** 当前正在处理的 `DependenciesBlock` */
		let currentBlock;

		/** 存储模块工厂和依赖映射 */
		let dependencies;
		let factoryCacheKey;
		let factoryCacheKey2;
		let factoryCacheValue;
		let listCacheKey1;
		let listCacheKey2;
		let listCacheValue;

		/** 追踪依赖排序和传递性任务的进度 */
		let inProgressSorting = 1;
		let inProgressTransitive = 1;

		/**
		 * 依赖排序完成后的回调函数
		 * @param {WebpackError=} err - 错误信息(如果有)
		 * @returns {void}
		 */
		const onDependenciesSorted = err => {
			if (err) return callback(err);

			// 如果 `sortedDependencies` 为空,且没有传递性任务,则直接回调 `callback`
			if (sortedDependencies.length === 0 && inProgressTransitive === 1) {
				return callback();
			}

			// 允许额外的并行任务处理
			this.processDependenciesQueue.increaseParallelism();

			for (const item of sortedDependencies) {
				inProgressTransitive++;
				this.handleModuleCreation(item, err => {
					if (err && this.bail) {
						if (inProgressTransitive <= 0) return;
						inProgressTransitive = -1;
						err.stack = err.stack; // 避免错误对象持有 `Compilation`
						onTransitiveTasksFinished(err);
						return;
					}
					if (--inProgressTransitive === 0) onTransitiveTasksFinished();
				});
			}
			if (--inProgressTransitive === 0) onTransitiveTasksFinished();
		};

		/**
		 * 依赖的传递性任务完成后的回调函数
		 * @param {WebpackError=} err - 错误信息(如果有)
		 * @returns {void}
		 */
		const onTransitiveTasksFinished = err => {
			if (err) return callback(err);
			this.processDependenciesQueue.decreaseParallelism();
			return callback();
		};

		/**
		 * 处理单个依赖项
		 * @param {Dependency} dep - 依赖
		 * @param {number} index - 依赖在 `block` 中的索引
		 * @returns {void}
		 */
		const processDependency = (dep, index) => {
			this.moduleGraph.setParents(dep, currentBlock, module, index);
			processDependencyForResolving(dep);
		};

		/**
		 * 解析依赖项,进行分类存储
		 * @param {Dependency} dep - 依赖
		 * @returns {void}
		 */
		const processDependencyForResolving = dep => {
			const resourceIdent = dep.getResourceIdentifier();
			if (resourceIdent !== undefined && resourceIdent !== null) {
				const category = dep.category;
				const constructor = dep.constructor;

				// 使用缓存优化
				if (factoryCacheKey === constructor) {
					if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
						listCacheValue.push(dep);
						return;
					}
				} else {
					const factory = this.dependencyFactories.get(constructor);
					if (factory === undefined) {
						throw new Error(`No module factory available for dependency type: ${constructor.name}`);
					}
					if (factoryCacheKey2 === factory) {
						factoryCacheKey = constructor;
						if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
							listCacheValue.push(dep);
							return;
						}
					} else {
						if (factoryCacheKey2 !== undefined) {
							if (dependencies === undefined) dependencies = new Map();
							dependencies.set(factoryCacheKey2, factoryCacheValue);
						}
						factoryCacheValue = new Map();
						factoryCacheKey = constructor;
						factoryCacheKey2 = factory;
					}
				}

				// 计算缓存 key
				const cacheKey = category === "esm" ? resourceIdent : `${category}${resourceIdent}`;
				let list = factoryCacheValue.get(cacheKey);
				if (list === undefined) {
					factoryCacheValue.set(cacheKey, (list = []));
					sortedDependencies.push({
						factory: factoryCacheKey2,
						dependencies: list,
						context: dep.getContext(),
						originModule: module
					});
				}
				list.push(dep);
				listCacheKey1 = category;
				listCacheKey2 = resourceIdent;
				listCacheValue = list;
			}
		};

		try {
			/** 采用队列方式遍历 `module` 及其 `DependenciesBlock` */
			const queue = [module];
			do {
				const block = queue.pop();
				if (block.dependencies) {
					currentBlock = block;
					let i = 0;
					for (const dep of block.dependencies) processDependency(dep, i++);
				}
				if (block.blocks) {
					for (const b of block.blocks) queue.push(b);
				}
			} while (queue.length !== 0);
		} catch (err) {
			return callback(err);
		}

		if (--inProgressSorting === 0) onDependenciesSorted();
	}

	/**
	 * 处理从 `unsafeCache` 恢复的模块,并进行依赖处理
	 * @private
	 * @param {Module} originModule - 原始模块
	 * @param {Dependency} dependency - 依赖项
	 * @param {Module} module - 缓存的模块
	 * @param {Callback} callback - 处理完成后调用的回调函数
	 */
	_handleNewModuleFromUnsafeCache(originModule, dependency, module, callback) {
		const moduleGraph = this.moduleGraph;

		// 设定模块解析关系
		moduleGraph.setResolvedModule(originModule, dependency, module);

		// 设置 `issuer`
		moduleGraph.setIssuerIfUnset(module, originModule !== undefined ? originModule : null);

		// 将模块添加到 Webpack 内部存储
		this._modules.set(module.identifier(), module);
		this.modules.add(module);

		// 兼容旧版 Webpack
		if (this._backCompat)
			ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);

		// 处理模块构建及其依赖
		this._handleModuleBuildAndDependencies(originModule, module, true, false, callback);
	}


	/**
	 * 处理从不安全缓存中添加已解析的模块到模块图。
	 * 该方法将缓存的模块与其原始模块和依赖项关联。
	 * 
	 * @private
	 * @param {Module} originModule 原始模块,即请求该依赖的模块
	 * @param {Dependency} dependency 需要解析的依赖
	 * @param {Module} module 缓存的模块,用于满足依赖
	 */
	_handleExistingModuleFromUnsafeCache(originModule, dependency, module) {
		const moduleGraph = this.moduleGraph;

		// 在模块图中将已解析的模块与依赖项关联
		moduleGraph.setResolvedModule(originModule, dependency, module);
	}

	/**
	 * @typedef {object} HandleModuleCreationOptions
	 * @property {ModuleFactory} factory 创建模块的工厂
	 * @property {Dependency[]} dependencies 模块的依赖项列表
	 * @property {Module | null} originModule 请求该模块的原始模块(可以为null)
	 * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo 创建模块时的上下文信息
	 * @property {string=} context 创建模块的上下文
	 * @property {boolean=} recursive 是否递归处理模块的依赖
	 * @property {boolean=} connectOrigin 是否将创建的模块与原始模块连接
	 * @property {boolean=} checkCycle 是否检查模块的循环依赖
	 */

	/**
	 * 处理模块的创建,包括处理其依赖项,并将其添加到模块图中。
	 * 该函数处理错误,应用工厂结果,并根据需要递归处理模块的依赖项。
	 * 
	 * @param {HandleModuleCreationOptions} options 模块创建的选项对象
	 * @param {ModuleCallback} callback 回调函数,用于处理结果
	 */
	handleModuleCreation(
		{
			factory,
			dependencies,
			originModule,
			contextInfo,
			context,
			recursive = true,
			connectOrigin = recursive,
			checkCycle = !recursive
		},
		callback
	) {
		const moduleGraph = this.moduleGraph;

		// 如果启用了性能分析,则跟踪模块分析信息
		const currentProfile = this.profile ? new ModuleProfile() : undefined;

		// 调用模块工厂创建模块并处理结果
		this.factorizeModule(
			{
				currentProfile,
				factory,
				dependencies,
				factoryResult: true,
				originModule,
				contextInfo,
				context
			},
			(err, factoryResult) => {
				// 应用工厂结果中的依赖项
				const applyFactoryResultDependencies = () => {
					const { fileDependencies, contextDependencies, missingDependencies } =
					/** @type {ModuleFactoryResult} */ (factoryResult);
					if (fileDependencies) {
						this.fileDependencies.addAll(fileDependencies);
					}
					if (contextDependencies) {
						this.contextDependencies.addAll(contextDependencies);
					}
					if (missingDependencies) {
						this.missingDependencies.addAll(missingDependencies);
					}
				};

				// 如果出现错误,处理错误并调用回调
				if (err) {
					if (factoryResult) applyFactoryResultDependencies();
					if (dependencies.every(d => d.optional)) {
						this.warnings.push(err);
						return callback();
					}
					this.errors.push(err);
					return callback(err);
				}

				const newModule = /** @type {ModuleFactoryResult} */ (factoryResult).module;

				// 如果没有创建模块,应用工厂依赖项并结束
				if (!newModule) {
					applyFactoryResultDependencies();
					return callback();
				}

				// 如果启用了性能分析,则设置模块的性能分析信息
				if (currentProfile !== undefined) {
					moduleGraph.setProfile(newModule, currentProfile);
				}

				// 将新创建的模块添加到模块图中
				this.addModule(newModule, (err, _module) => {
					if (err) {
						applyFactoryResultDependencies();
						if (!err.module) {
							err.module = _module;
						}
						this.errors.push(err);

						return callback(err);
					}

					const module = /** @type {Module & { restoreFromUnsafeCache?: Function }} */ (_module);

					// 如果启用了不安全缓存且模块可以缓存,将模块与依赖项关联
					if (
						this._unsafeCache &&
					/** @type {ModuleFactoryResult} */ (factoryResult).cacheable !== false &&
						module.restoreFromUnsafeCache &&
						this._unsafeCachePredicate(module)
					) {
						const unsafeCacheableModule = /** @type {Module & { restoreFromUnsafeCache: Function }} */ (module);
						for (let i = 0; i < dependencies.length; i++) {
							const dependency = dependencies[i];
							moduleGraph.setResolvedModule(
								connectOrigin ? originModule : null,
								dependency,
								unsafeCacheableModule
							);
							unsafeCacheDependencies.set(dependency, unsafeCacheableModule);
						}
						if (!unsafeCacheData.has(unsafeCacheableModule)) {
							unsafeCacheData.set(
								unsafeCacheableModule,
								unsafeCacheableModule.getUnsafeCacheData()
							);
						}
					} else {
						applyFactoryResultDependencies();
						for (let i = 0; i < dependencies.length; i++) {
							const dependency = dependencies[i];
							moduleGraph.setResolvedModule(
								connectOrigin ? originModule : null,
								dependency,
								module
							);
						}
					}

					// 如果模块尚未设置issuer,则设置它
					moduleGraph.setIssuerIfUnset(
						module,
						originModule !== undefined ? originModule : null
					);

					// 如果模块与新创建的模块不同,合并性能分析数据
					if (module !== newModule && currentProfile !== undefined) {
						const otherProfile = moduleGraph.getProfile(module);
						if (otherProfile !== undefined) {
							currentProfile.mergeInto(otherProfile);
						} else {
							moduleGraph.setProfile(module, currentProfile);
						}
					}

					// 处理模块构建和依赖项
					this._handleModuleBuildAndDependencies(
						originModule,
						module,
						recursive,
						checkCycle,
						callback
					);
				});
			}
		);
	}

	/**
	 * 处理模块的构建并递归处理其依赖项。
	 * 该函数检查循环依赖,处理模块的依赖项,并调用回调。
	 * 
	 * @private
	 * @param {Module} originModule 原始模块,即触发构建的模块
	 * @param {Module} module 当前正在处理的模块
	 * @param {boolean} recursive 是否递归处理模块的依赖项
	 * @param {boolean} checkCycle 是否检查模块的循环依赖
	 * @param {ModuleCallback} callback 处理结果的回调函数
	 */
	_handleModuleBuildAndDependencies(
		originModule,
		module,
		recursive,
		checkCycle,
		callback
	) {
		// 在构建期间检查是否有循环依赖
		/** @type {Set<Module> | undefined} */
		let creatingModuleDuringBuildSet;
		if (checkCycle && this.buildQueue.isProcessing(originModule)) {
			// 跟踪构建依赖
			creatingModuleDuringBuildSet =
				this.creatingModuleDuringBuild.get(originModule);
			if (creatingModuleDuringBuildSet === undefined) {
				creatingModuleDuringBuildSet = new Set();
				this.creatingModuleDuringBuild.set(
					originModule,
					creatingModuleDuringBuildSet
				);
			}
			creatingModuleDuringBuildSet.add(module);

			// 如果模块被另一个模块阻塞,则查找循环并抛出错误
			const blockReasons = this.creatingModuleDuringBuild.get(module);
			if (blockReasons !== undefined) {
				const set = new Set(blockReasons);
				for (const item of set) {
					const blockReasons = this.creatingModuleDuringBuild.get(item);
					if (blockReasons !== undefined) {
						for (const m of blockReasons) {
							if (m === module) {
								return callback(new BuildCycleError(module));
							}
							set.add(m);
						}
					}
				}
			}
		}

		// 开始构建模块
		this.buildModule(module, err => {
			if (creatingModuleDuringBuildSet !== undefined) {
				creatingModuleDuringBuildSet.delete(module);
			}
			if (err) {
				if (!err.module) {
					err.module = module;
				}
				this.errors.push(err);

				return callback(err);
			}

			// 如果不是递归处理,非递归地处理模块的依赖项
			if (!recursive) {
				this.processModuleDependenciesNonRecursive(module);
				callback(null, module);
				return;
			}

			// 避免循环依赖引起的死锁
			if (this.processDependenciesQueue.isProcessing(module)) {
				return callback(null, module);
			}

			// 递归处理模块的依赖项
			this.processModuleDependencies(module, err => {
				if (err) {
					return callback(err);
				}
				callback(null, module);
			});
		});
	}
相关推荐
剪刀石头布啊15 分钟前
浏览器进程与事件循环
前端·浏览器
剪刀石头布啊16 分钟前
浏览器渲染原理
前端·浏览器
日记成书43 分钟前
【HTML 基础教程】HTML 表格
前端·html
木木黄木木1 小时前
HTML5贪吃蛇游戏开发经验分享
前端·html·html5
无名之逆1 小时前
hyperlane:Rust HTTP 服务器开发的不二之选
服务器·开发语言·前端·后端·安全·http·rust
李鸿耀1 小时前
前端包管理工具演进史:从 npm 到 pnpm 的技术革新
前端·面试
麓殇⊙1 小时前
前端基础知识汇总
前端
MariaH1 小时前
邂逅jQuery库
前端
Jenlybein1 小时前
学完 Vue3 记不牢?快来看这篇精炼Vue3笔记复习一下 [ Route 篇 ]
前端·vue.js
页面魔术1 小时前
[译]专访尤雨溪: 2025年有什么计划?
前端·vue.js·vite