webpack 构建阶段介绍
Webpack 的编译流程可以分解为 7 个核心阶段,结合 Webpack 5 源码(以 webpack/webpack 仓库主分支为准)的结构实现,这里为您进行详细阐述:
一、初始化阶段
入口文件:lib/webpack.js
- 参数校验与配置合并:
const createCompiler = options => {
// 验证配置有效性
const webpackOptionsValidationErrors = validateSchema(
webpackOptionsSchema,
options
);
// 合并默认配置(@webpack/configuration包)
const compiler = new Compiler(options.context);
compiler.options = new WebpackOptionsApply().process(options, compiler);
}
- 核心对象实例化:
- 创建
Compiler(顶层控制对象)实例(lib/Compiler.js) - 创建
Compilation工厂对象(lib/Compilation.js) - 初始化内置插件系统(Tapable 继承实现)
关键源码示例:
// 初始化Compiler
class Compiler {
constructor(context) {
this.hooks = Object.freeze({
beforeRun: new AsyncSeriesHook(["compiler"]),
run: new AsyncSeriesHook(["compiler"]),
// ...超过30个生命周期钩子
});
// ...其他初始化
}
}
二、模块解析(Resolve)阶段
核心类:ResolverFactory(lib/ResolverFactory.js)
- 解析路径策略:
- 通过 EnhancedResolver 处理模块路径的复杂性(aliases、extensions 等)
- 使用
enhanced-resolve包实现多级缓存机制
关键代码流程:
compiler.resolverFactory.hooks.resolver
.for('normal')
.tap('WebpackOptionsApply', () => {
const resolver = createResolver({
fileSystem: compiler.inputFileSystem,
// ...包含39种解析配置参数
});
return resolver;
});
三、模块加载(Loaders)阶段
核心处理器:NormalModule(lib/NormalModule.js)
- Loader 执行链:
runLoaders(
resource: string,
loaders: LoaderItem[],
context: LoaderContext,
callback: (err, result) => void
)
- 源码转换流程:
- 通过
LoaderRunner(lib/LoaderRunner.js)管道式处理 - 支持 pitching loader 机制(反序执行 pitch 方法)
关键数据结构:
class NormalModule extends Module {
constructor({
// ...,
loaders, // 最终生成的loader链
resource
}) {
// ...初始化处理策略
}
}
四、依赖图谱构建阶段
核心算法:深度优先遍历
- AST 分析:
惧使用acorn库生成 AST
const parser = new JavascriptParser();
parser.parse(source, {
sourceType: module.buildInfo.moduleArgument ? "module" : "script",
// ...携带15+种分析配置
});
- 依赖关系收集:
- 遍历 AST 时识别
import/require等语法 - 通过
ModuleGraph类(lib/ModuleGraph.js)记录模块间依赖
五、Chunk 生成阶段
优化策略:
- 使用
SplitChunksPlugin(lib/optimize/SplitChunksPlugin.js)进行代码拆分 - Entry dependencies 处理入口点依赖
关键代码:
// 在Compilation实例中生成chunk
compilation.addEntry(context, entry, options, err => {
// 内部调用_addModuleChain进行模块链式处理
});
六、代码生成阶段
核心方法:codeGeneration()(lib/Compilation.js)
处理流程:
- 调用
Template.apply()生成运行时代码 - 通过
MainTemplate(生产入口代码)和ChunkTemplate(生成非入口代码)处理不同类型输出 - 使用
renderManifest钩子允许插件参与渲染
源码结构示例:
// 代码生成核心方法
compilation.codeGeneration({
dependencyTemplates,
runtimeTemplate,
moduleTemplates,
type: "runtime",
// ...19种生成配置参数
});
七、输出阶段
核心类:Compiler.writeAssets()(`lib/Compiler.js``
步骤明细:
- 调用
emitAssets()触发插件钩子 - 通过
outputFileSystem(默认内存文件系统)写入磁盘 - 处理 hash 更新与缓存策略
关键输出逻辑:
const emitFiles = err => {
// ...校验输出目录等前置操作
this.outputFileSystem.writeFile(targetPath, content, callback);
// 触发assetEmitted等钩子
};
架构亮点分析
- 可插拔的 Hook 系统:
- 基于
Tapable实现 200+ 生命周期钩子 - 插件系统可在任意阶段注入逻辑
- 缓存体系:
- MemoryCachePlugin 实现内存级缓存
- 支持持久化缓存(
cache: { type: 'filesystem' })
- 多线程优化:
- 在 Parser 阶段使用
worker-farm并行处理 - 限制线程池大小防止资源耗尽
通过以上阶段分析可以看到,Webpack 通过模块化架构设计和精细的阶段划分,实现了高度可扩展的构建流程。理解各阶段的实现机制对优化构建性能和开发高级插件至关重要。

浙公网安备 33010602011771号