Webpack 的构建流程是怎样的?从启动到输出经历了哪些主要步骤?
Webpack 的构建流程是一个基于事件驱动(Tapable)的流水线系统。简单来说,它从入口文件开始,递归地解析所有依赖,通过 Loader 转译文件,通过 Plugin 注入钩子逻辑,最终将所有代码打包成浏览器可执行的 Chunk 并输出为静态资源。
整个构建流程大体可以分为 三个核心阶段:初始化阶段、编译构建阶段(Compile) 和 输出生成阶段(Output)。
一、 详细构建流程(共 8 个主要步骤)
阶段一:初始化阶段(Initialization)
初始化参数(Initialize Options)
- 从配置文件(如
webpack.config.js)和 CLI 命令行中读取并合并参数,形成最终的options对象。
- 从配置文件(如
创建 Compiler 对象(Create Compiler)
- 用上一步得到的参数初始化
Compiler对象。 Compiler是 Webpack 的“大管家”,贯穿整个生命周期,负责管理配置、监听事件和触发构建。
- 用上一步得到的参数初始化
加载插件(Init Plugins)
- 遍历配置文件中的
plugins数组,执行每个插件的apply方法,并将compiler对象作为参数传入。 - 插件在此处向 Webpack 的各种钩子(Hooks)注册监听函数,以便在后续阶段干预构建流程。
- 遍历配置文件中的
阶段二:编译构建阶段(Compilation)—— 最核心的阶段
确定入口(Entry)
- 根据配置中的
entry找到所有的入口文件。 - 触发
compiler.run()并创建Compilation对象(负责代表“这一次”的编译过程)。
- 根据配置中的
编译模块(Build Module / Loader 处理)
- 读取文件:从入口文件开始,读取源码。
- 调用 Loader:根据
module.rules中匹配的规则,将文件交给相应的 Loader 处理(如.vue-> JS,scss-> CSS)。Loader 按照从右到左/从下到上的顺序执行,将非 JS 资源转换为 JS 代码或标准的 AST。 - 解析 AST 寻找依赖:使用 Babel/Acorn 将 Loader 转译后的代码解析成抽象语法树(AST)。
- 收集依赖:分析 AST 中的
import、require()等语句,找到当前模块依赖的其他模块。
递归编译依赖(Recursive Build)
- 对第 5 步中找到的依赖模块,递归地执行“读取 -> Loader转译 -> 解析AST -> 收集依赖”的过程。
- 直到所有入口文件及其依赖的所有模块都被编译完成,形成一棵模块依赖图(Module Graph)。
阶段三:输出生成阶段(Output)
合成 Chunk 并渲染(Create Chunks & Assets)
- 拆分 Chunk:根据入口文件(Entry)以及动态导入(
import())、代码分割配置(optimization.splitChunks),将编译后的 Modules 组合成不同的 Chunk(代码块)。 - 生成 Assets:将 Chunk 转换为对应的代码模板(比如加上 Webpack 独有的模块加载器
__webpack_require__),生成一个个包含最终代码的文件(Assets/Files,此时还在内存中)。
- 拆分 Chunk:根据入口文件(Entry)以及动态导入(
输出完成(Emit Files)
- 确定输出路径:根据配置
output.path和output.filename,确定文件输出的最终路径和文件名。 - 写入文件系统:触发
emit事件(这是修改输出内容的最后机会),然后将内存中的资源文件写入磁盘(Dist 目录)。 - 触发
done事件,构建结束。
- 确定输出路径:根据配置
二、 一图胜千言(流程简图)
plaintext
[ 读取 Config / CLI 参数 ]
↓
[ 初始化 Compiler 并挂载 Plugins ]
↓
[ 执行 compiler.run() → 创建 Compilation ]
↓
[ 从 Entry 节点开始解析 ]
↓
[ 匹配 Loader 转换文件内容 (例如 Sass->CSS, ES6->ES5) ]
↓
[ 解析 AST,提取 import/require 依赖 ]
↓
[ 递归处理所有依赖模块 (形成 Module Graph) ]
↓
[ 将 Modules 组合成 Chunks (代码分割/合并) ]
↓
[ 使用 Template 渲染 Chunk 成为 Assets (带 Webpack Runtime) ]
↓
[ 触发 emit 钩子,将 Assets 写入 Output 硬盘目录 ]
↓
[ 完成构建 (done 阶段) ]
三、 两个核心概念:Compiler 与 Compilation
在理解构建流程时,必须区分这两个极其重要的对象:
Compiler:- 代表: Webpack 的整个生命周期(从启动到关闭)。
- 全局唯一: 在启动时创建一次。
- 作用: 保存了 Webpack 的完整配置,暴露了全局生命周期 Hook(如
run,make,emit,done)。
Compilation:- 代表: 一次单独的编译构建过程。
- 多次创建: 在热更新(HMR)或开发模式下,每次修改文件重新打包时,Webpack 都会创建一个新的
Compilation对象。 - 作用: 保存了当前的模块资源(Modules)、依赖图(Module Graph)、 Chunk 以及最终生成的 Asset 信息。
四、 总结(口语化速记)
Webpack 的构建流程可以概括为 3 个词:
- 初始化:合并配置,装载插件,准备环境。
- 构建(最重):从 Entry 出发,Loader 翻转代码,AST 找依赖,递归形成关系树。
- 输出:代码打包合并为 Chunk,生成文件写入 Dist。
右滑查看面试常问