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