很多前端开发者每天都在用 Webpack,对着 webpack.config.js 复制粘贴。但你是否想过,当你按下 npm run build 的那一刻,Webpack 内部到底发生了什么?
理解 Webpack 的构建流程,不仅仅是为了通过面试(虽然这是高频考点),更是为了让你在遇到"构建失败"、"打包太慢"或"需要写插件"时,能够上帝视角般地定位问题。
如果把 Webpack 比作一个超级面包工厂,那么构建流程就是从采购面粉(源代码)到包装出库(最终 Bundle)的全过程。我们将这个过程拆解为三个核心阶段。
第一阶段:初始化 (Initialization) ------ 工厂启动
这阶段主要是在做准备工作,读取配置,把机器开起来。
1. 初始化参数
Webpack 的第一步是"阅读说明书"。它会将配置文件 (webpack.config.js) 中的配置与 Shell 命令行参数(如 --mode production)进行合并,得到最终的配置对象。
2. 实例化 Compiler
用上一步得到的参数,初始化一个 Compiler 对象。
- 地位:它是 Webpack 的"厂长",全局唯一。
- 作用:它保存了完整的配置环境,负责指挥接下来的所有生产工作。
3. 加载插件 (Load Plugins)
Webpack 遍历配置中的 plugins 数组,调用每个插件的 apply 方法。
- 关键动作 :插件们此时开始在 Compiler 的各个生命周期钩子(Hooks)上进行注册监听。这就好比工厂里的各种传感器和机械臂已经就位,准备在特定的时间点干活。
4. 确定入口
根据配置中的 entry,找出所有的入口文件,准备开始真正的构建。
涉及的核心 Hooks :
entryOption,afterPlugins,run
第二阶段:构建阶段 (Make) ------ 原料加工
这是最核心、最耗时的阶段。Webpack 从入口文件出发,像爬虫一样解析整个项目。
1. 编译模块 (Compile)
从 entry 文件开始,Webpack 会创建一个 Module 对象。
2. Loader 转译
"翻译官"进场 。Webpack 原生只认识 JS 和 JSON。如果遇到 .css, .vue, .ts 等文件,它会去配置里找对应的 module.rules。
- 执行顺序:Loader 通常是从右向左(或从下向上)执行的。
- 结果:所有非 JS 文件最终都被"翻译"成了标准的 JS 内容。
3. 解析代码 (Parse & AST)
Loader 翻译完后,Webpack 使用解析器(通常是 Acorn)将 JS 代码转换成 AST (抽象语法树) 。
4. 分析依赖 (Dependency Graph)
Webpack 遍历 AST,寻找 import、require 等语句。一旦发现依赖,就将其收集起来,加入到待处理列表中。
5. 递归编译
对上一步找到的每一个依赖模块,重复执行上述的 "创建 -> Loader转译 -> AST解析 -> 分析依赖" 过程。 这个过程一直持续到所有模块都处理完毕。
6. 完成模块图
递归结束后,Webpack 内存中就形成了一棵完整的依赖树(Dependency Graph) 。此时,Webpack 清楚地知道项目中哪个文件依赖了哪个文件。
涉及的核心 Hooks :
make,buildModule,normalModuleLoader,succeedModule
第三阶段:生成阶段 (Seal & Emit) ------ 装箱打包
原料都处理好了,现在的任务是将零散的模块组装成最终的输出文件。
1. 封装 (Seal)
compilation.seal() 被调用。此时,Webpack 停止接收新的模块。
- 优化时机:Tree Shaking(去除无用代码)等优化操作通常就在这里进行分析。
2. 组装 Chunk (Chunking)
根据入口(Entry)和代码分割(SplitChunks)规则,Webpack 将多个 Module 合并成一个或多个 Chunk(代码块) 。
- 例子:你的
main.js引用了React。React 可能会被分包成vendors~main.chunk.js。
3. 生成资源 (Assets)
Webpack 根据 Chunk 的内容,套用模板(Template),生成最终的代码字符串。 此时,资源保存在内存 的 compilation.assets 对象中,形式是 Key-Value 结构。
4. 输出文件 (Emit)
这是修改文件的最后机会 (很多插件会在 emit 钩子修改最终产物)。 Webpack 根据配置的 output.path 和 filename,将内存中的 assets 真正写入到文件系统(磁盘) 。
涉及的核心 Hooks :
seal,optimizeChunks,emit,done
总结:流程速查图

附:高频面试题锦囊
看完流程,这三个问题你应该能秒答:
Q1: Loader 和 Plugin 的本质区别是什么?
- Loader :工作在"构建阶段"(阶段二),本质是转换器(如把 Less 转 CSS),专注于文件内容的转换。
- Plugin :贯穿整个生命周期,本质是扩展器。它监听 Webpack 广播出的各种事件(Hooks),在合适的时机改变输出结果(如压缩代码、注入环境变量)。
Q2: Tree Shaking 发生在什么时候?
- 发生在 Seal (封装) 阶段。Webpack 依靠 ES6 Module 的静态结构,分析出哪些 export 没有被引用,然后在生成 Chunk 时将死代码剔除。
Q3: Babel 在哪里工作?
- Babel 是作为一个 Loader 工作的。它在 AST 解析之前,将 ES6+ 源码转译为 Webpack 能更好理解(或兼容性更好)的 ES5 代码。