webpack 核心编译器 第五节

137 阅读3分钟

这部分 Webpack 源码主要负责模块的创建和管理:

  • _factorizeModule:用于解析模块,调用工厂创建模块,并处理依赖项。
  • addModuleChainaddModuleTree:用于递归创建模块及其依赖,构建模块树。
  • addEntry:用于添加入口模块。
  • addInclude:用于添加额外的包含依赖。

这部分代码的核心功能是利用 模块工厂 来创建 Webpack 依赖的模块,并管理其依赖关系,从而形成 Webpack 的模块构建流程。


	/**
	 * 解析并创建模块
	 * @param {FactorizeModuleOptions} options 选项对象,包含模块创建的相关参数
	 * @param {ModuleOrFactoryResultCallback} callback 处理完成后的回调
	 * @returns {void}
	 */
	_factorizeModule(
		{
			currentProfile, // 当前模块的性能分析信息
			factory, // 模块工厂
			dependencies, // 依赖数组
			originModule, // 该模块的来源模块
			factoryResult, // 是否需要返回工厂结果
			contextInfo, // 上下文信息
			context // 解析依赖的上下文路径
		},
		callback
	) {
		// 如果启用了性能分析,记录工厂开始时间
		if (currentProfile !== undefined) {
			currentProfile.markFactoryStart();
		}

		// 调用工厂的 create 方法来创建模块
		factory.create(
			{
				contextInfo: {
					issuer: originModule ? originModule.nameForCondition() : "", // 来源模块的名称
					issuerLayer: originModule ? originModule.layer : null, // 来源模块的层
					compiler: this.compiler.name, // 编译器名称
					...contextInfo // 额外的上下文信息
				},
				resolveOptions: originModule ? originModule.resolveOptions : undefined, // 解析选项
				context: context || (originModule ? originModule.context : this.compiler.context), // 解析依赖的上下文
				dependencies // 依赖项
			},
			(err, result) => {
				if (result) {
					// 兼容旧版本 Webpack,确保 `result.module` 存在
					if (result.module === undefined && result instanceof Module) {
						result = { module: result };
					}

					// 处理模块的依赖文件信息
					if (!factoryResult) {
						const { fileDependencies, contextDependencies, missingDependencies } = result;
						if (fileDependencies) this.fileDependencies.addAll(fileDependencies);
						if (contextDependencies) this.contextDependencies.addAll(contextDependencies);
						if (missingDependencies) this.missingDependencies.addAll(missingDependencies);
					}
				}

				// 处理错误
				if (err) {
					const notFoundError = new ModuleNotFoundError(
						originModule,
						err,
						dependencies.map(d => d.loc).find(Boolean) // 依赖的代码位置
					);
					return callback(notFoundError, factoryResult ? result : undefined);
				}

				// 如果 result 为空,直接回调
				if (!result) return callback();

				// 记录工厂创建结束的时间
				if (currentProfile !== undefined) {
					currentProfile.markFactoryEnd();
				}

				// 执行回调,返回创建的模块
				callback(null, factoryResult ? result : result.module);
			}
		);
	}

	/**
	 * 添加模块链,创建一个模块并解析它的依赖
	 * @param {string} context 依赖解析的上下文路径
	 * @param {Dependency} dependency 需要解析的依赖
	 * @param {ModuleCallback} callback 解析完成后的回调
	 * @returns {void}
	 */
	addModuleChain(context, dependency, callback) {
		return this.addModuleTree({ context, dependency }, callback);
	}

	/**
	 * 递归添加模块,构建模块依赖树
	 * @param {object} options 选项
	 * @param {string} options.context 解析依赖的上下文路径
	 * @param {Dependency} options.dependency 需要解析的依赖
	 * @param {Partial<ModuleFactoryCreateDataContextInfo>=} options.contextInfo 额外的上下文信息
	 * @param {ModuleCallback} callback 解析完成后的回调
	 * @returns {void}
	 */
	addModuleTree({ context, dependency, contextInfo }, callback) {
		// 检查 dependency 是否是有效的 Dependency 实例
		if (typeof dependency !== "object" || dependency === null || !dependency.constructor) {
			return callback(new WebpackError("Parameter 'dependency' must be a Dependency"));
		}

		// 获取依赖对应的工厂
		const Dep = /** @type {DepConstructor} */ (dependency.constructor);
		const moduleFactory = this.dependencyFactories.get(Dep);

		// 如果找不到对应的工厂,抛出错误
		if (!moduleFactory) {
			return callback(new WebpackError(
				`No dependency factory available for this dependency type: ${dependency.constructor.name}`
			));
		}

		// 处理模块的创建
		this.handleModuleCreation(
			{
				factory: moduleFactory,
				dependencies: [dependency],
				originModule: null,
				contextInfo,
				context
			},
			(err, result) => {
				// 处理错误
				if (err && this.bail) {
					callback(err);
					this.buildQueue.stop();
					this.rebuildQueue.stop();
					this.processDependenciesQueue.stop();
					this.factorizeQueue.stop();
				} else if (!err && result) {
					callback(null, result);
				} else {
					callback();
				}
			}
		);
	}

	/**
	 * 添加一个入口模块
	 * @param {string} context 入口模块的上下文路径
	 * @param {Dependency} entry 入口依赖
	 * @param {string | EntryOptions} optionsOrName 入口的选项或名称(Webpack 6 之后仅支持选项)
	 * @param {ModuleCallback} callback 解析完成后的回调
	 * @returns {void}
	 */
	addEntry(context, entry, optionsOrName, callback) {
		// Webpack 6 之后移除对字符串名称的支持
		const options = typeof optionsOrName === "object"
			? optionsOrName
			: { name: optionsOrName };

		// 添加入口项
		this._addEntryItem(context, entry, "dependencies", options, callback);
	}

	/**
	 * 添加 include 依赖项
	 * @param {string} context 依赖解析的上下文路径
	 * @param {Dependency} dependency 依赖项
	 * @param {EntryOptions} options 入口选项
	 * @param {ModuleCallback} callback 解析完成后的回调
	 * @returns {void}
	 */
	addInclude(context, dependency, options, callback) {
		this._addEntryItem(context, dependency, "includeDependencies", options, callback);
	}