这部分 Webpack 源码主要负责模块的创建和管理:
_factorizeModule:用于解析模块,调用工厂创建模块,并处理依赖项。addModuleChain和addModuleTree:用于递归创建模块及其依赖,构建模块树。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);
}