初始化阶段
- 参数处理 合并默认参数和配置参数 校验配置 合并最终配置
- 创建
compiler对象 - 处理用户定义的
plugins调用plugin的apply - 调用new
WebpackOptionsApply().apply处理webpack内置插件- 注入
EntryOptionPlugin插件,处理entry配置 - 根据
devtool的值,判断后续用哪个插件处理sourcemap - 注入
runtimePlugin,用于根据代码内容动态注入webpack运行时
- 注入
compiler实例创建成功compiler.compile()
构建阶段
handleModuleCreate根据文件类型构建module- 通过
loader-runner的runloaders将各类文件资源转换为js - 通过
acorn将js解析为AST - 遍历
AST,在HarmonyExportDependencyParserPlugin插件监听exportImportSpecifier钩子,解读JS文本对应的资源依赖 - 使用
module对象的addDependency将依赖对象加入到module依赖列表 AST遍历结束,调用module.handleParseResult处理依赖列表- 对于新增的依赖 再通过第一步的
handleModuleCreate创建module - 重复前面的操作。等所有的依赖处理完成,构建结束
生成阶段
在构建阶段生成的modules,在此阶段会生成chunks输出
- 构建本次编译的
chunkGraph对象 - 遍历
compilation.modules集合,将module按照entry/动态引入,分配给不同的chunk对象 - 遍历完成后,得到完整的
chunks集合对象,调用creatXxxAssets方法 creatXxxAssets方法遍历module/chunk,调用compilation.emitAssets将assets信息记录到compilation.assets中- 触发
seal回调,控制流回到compiler对象
创建chunk的过程示例:
const path = require("path");
module.exports = {
mode: "development",
context: path.join(__dirname),
entry: {
a: "./src/index-a.js",
b: "./src/index-b.js",
},
output: {
filename: "[name].js",
path: path.join(__dirname, "./dist"),
},
devtool: false,
target: "web",
plugins: [],
};
此时index-a中依赖c,动态引入d
index-b中依赖c,e

两个entry文件分别生成各自的chunk,动态导入的d也生成一个chunk。chunk a中包含index-a.js和c,chunk b 中包含index-b.js、c、e。c同时包含在两个chunk中,无疑增大了项目体积。因此,webpack提供了一些插件如SplitChunksPlugin,在之前的基础上进一步优化chunk结构