引言
时至今日,Webpack 已迭代到 5.x 版本,其功能模块的扩充和复杂度的提升使得源码学习成本陡增。官方文档的晦涩表述更是让许多开发者望而却步。然而,理解 Webpack 的核心原理对优化构建流程、定制化打包方案至关重要。本文将通过简化流程和代码示例,剖析 Webpack 的运作机制,帮助读者从本质层面掌握其核心能力,突破"配置工程师"的局限。
Webpack 的核心能力
Webpack 本质上是一个 JavaScript 应用程序的静态模块打包器。它将应用程序中的资源(JS、CSS、图片等)视为模块,分析依赖关系后打包成静态资源文件,官网的动画就能很好的诠释这一点。

其核心能力可概括为:
- 模块化整合:将分散的代码按依赖关系组织成 chunk。
- 资源转换:通过 Loader 系统处理非 JS 文件。
- 扩展性:通过 Plugin 系统在构建生命周期中注入自定义逻辑。
基础使用
初始化项目
ba
npm init -y
npm install webpack webpack-cli --save-dev
目录结构
cs
├── package.json
├── webpack.config.js # 配置文件
└── src
├── index.js # 入口文件
├── a.js
└── b.js
webpack.config.js
js
module.exports = {
mode: "development", // 开发模式(不压缩代码)
entry: "./src/index.js",
devtool: "source-map" // 生成源码映射
};
src/index.js
js
console.log("index module");
const a = require('./a.js');
console.log(a);
src/a.js
js
console.log("a module");
const b = require('./b.js');
console.log(b);
module.exports = 'a';
src/b.js
js
console.log("b module");
module.exports = 'b';
打包结果分析
执行 npx webpack
后生成的 dist/main.js
:
js
(() => {
// 初始化、定义了一个模块对象,key为模块的路径,value函数里面的内容就是我们书写的模块的代码
var __webpack_modules__ = ({
"./src/a.js": ((module, __unused_webpack_exports, __webpack_require__) => {
console.log("a module");
const b = __webpack_require__("./src/b.js");
console.log(b);
module.exports = 'a';
}),
"./src/b.js": ((module) => {
console.log("b module");
module.exports = 'b';
})
});
// 模块缓存
var __webpack_module_cache__ = {};
// 定义__webpack_require__函数,就是我们在代码中使用的require函数
function __webpack_require__(moduleId) {
// 查找缓存中是否有该模块
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
var module = __webpack_module_cache__[moduleId] = {
exports: {}
};
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
// 入口文件 src/index.js
(() => {
console.log("index module");
const a = __webpack_require__(/*! ./a.js */ "./src/a.js");
console.log(a);
})();
})()
打包后的核心内容包含:
- 模块映射表:以路径为 key,模块代码为 value。
- 模块缓存:避免重复加载。
- require 函数:实现模块依赖解析。
- 入口执行逻辑:立即执行入口模块代码。
那核心问题来了,Webpack 是如何将我们的源代码打包成 dist/main.js 的?
Webpack 的工作流程
Webpack 的进行打包的工作流程可以分为三个主要阶段:
- 初始化阶段:合并配置,创建 Compiler 对象,加载插件。
- 编译阶段:从入口递归分析依赖,构建模块依赖图。
- 输出阶段:按 chunk 生成文件并写入磁盘。

初始化阶段
初始化阶段是 Webpack 打包流程的起点,关键步骤:
- 合并配置(CLI 参数 + 配置文件 + 默认配置)。
- 创建 Compiler 对象(核心控制器)。
- 加载插件并绑定生命周期钩子。
编译阶段
编译阶段是 Webpack 处理模块的核心阶段,核心过程:
- 模块转译:Loader 将非 JS 文件转为 JS,生成 AST。
- 依赖分析:遍历 AST 提取模块依赖,递归处理。
- 生成模块表:记录模块代码、依赖关系和唯一 ID。
js
// 编译后的模块表示例
const modules = [
{
id: "./src/a.js",
dependencies: ["./src/b.js"],
code: `/* 转换后的代码 */`
}
];
编译流程图:

输出阶段
输出阶段是 Webpack 打包流程的最后阶段,主要包括以下步骤:
- 生成 chunk:按入口和动态导入规则拆分模块。
- 资源封装:将 chunk 转为包含运行时逻辑的 IIFE 函数。
- 文件写入:根据输出配置生成最终文件。
经过这三个阶段,Webpack 就实现了将我们的源代码打包成了最终的工程文件了。
但是在构建的整个过程中,由于浏览器只能认识** html、css、js
** 这几种格式的文件,所以需要对其他格式的文件进行转换,这个就需要一个工具来实现,就是 Loader 系统
。
Loader 系统
Loader系统可以将非 JS 文件(如 CSS、图片)转换为 Webpack 可识别的模块,从而纳入到 Webpack 的打包流程中。

Loader 的工作原理
Loader 通过定义一个函数,将输入的内容转换为输出的内容。Webpack 会将 Loader 链式调用,每个 Loader 处理完内容后,会将结果传递给下一个 Loader,直到链尾。 Loader 的基本结构如下:
javascript
module.exports = function (content) {
// 处理内容
return processedContent;
};
在 Webpack 配置中,可以通过 module.rules
来指定 Loader:
javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
],
},
};
在这个配置中,test
指定了要匹配的文件类型,use
指定了要使用的 Loader 。当 Webpack 处理文件时,会根据文件类型选择对应的 Loader 链来处理文件。
除了文件转换之外,Webpack 也需要在特定时机进行一些处理,这个时候需要一个接口的设计,就是 Plugin 系统
Plugin 系统
Plugin 系统是 Webpack 功能扩展的重要机制。通过 Plugin,开发者可以实现各种功能,如代码压缩、提取 CSS、生成 HTML 等。
Plugin的工作原理
Plugin 通过监听 Webpack 的生命周期事件,在特定的时机介入编译过程。Webpack 提供了丰富的钩子(hooks),Plugin 可以通过注册这些钩子来实现功能扩展。

Plugin 的基本结构如下:
javascript
class SomePlugin {
apply(compiler) {
// 注册钩子
compiler.hooks.someHook.tap('SomePlugin', () => {
// 实现插件功能
});
}
}
在 apply
函数中,Plugin 可以通过 compiler.hooks
访问各种钩子,并注册回调函数。当 Webpack 执行到对应的生命周期阶段时,会触发这些钩子,从而执行 Plugin 的功能。
总结
Webpack 的核心原理可归结为模块化 、依赖分析 与资源整合。通过理解其工作流程的三阶段(初始化、编译、输出),能更高效地配置优化策略,定制 Loader/Plugin 解决个性化需求。
尽管 Webpack 的学习曲线陡峭,但掌握其核心机制后,面对复杂的构建场景(如性能优化、微前端打包)时,开发者将不再受限于"黑盒"工具,而是能够通过扩展能力实现精准控制。