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);
			});
		});
	}
相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax