1. 为什么需要 webpack
在早期前端开发中,我们会直接用 <script> 标签引入多个 JS 文件,这样会导致:
- 依赖关系混乱:JS 文件顺序需要手动控制
- 全局作用域污染:变量容易冲突
- 资源无法统一管理:CSS、图片、字体等需要单独处理
- 无法使用模块化:ES Module、CommonJS 等在浏览器中不被原生支持
webpack 的出现就是为了解决这些问题:
webpack 是一个静态模块打包器(module bundler) ,它会分析你的项目结构,找到 JS 模块以及浏览器不能直接运行的拓展语言(如 TypeScript、JSX、Sass),并将其打包为合适的格式供浏览器使用。
2. webpack 的核心原理
2.1 核心思想
- 一切皆模块在 webpack 看来,不仅 JS 文件是模块,CSS、图片、字体等也都可以被当作模块引入和使用。
- 按需加载打包时可以将代码分割成多个块(chunk),运行时只加载当前需要的部分,提高性能。
- 递归解析依赖从入口文件开始,递归地解析所有依赖模块,形成依赖图(Dependency Graph)。
2.2 工作流程
webpack 的打包过程可以分为三个核心阶段:
(1)初始化阶段
- 启动 webpack,读取并合并配置参数(
webpack.config.js、CLI 参数、默认配置)。 - 创建 Compiler 对象,负责整个构建过程。
- 加载所有配置的插件。
(2)编译阶段
-
解析入口文件(如
src/index.js)。 -
构建依赖图:
- 使用 loader 对模块进行转换(例如:
babel-loader将 ES6+ 转成 ES5,css-loader处理 CSS)。 - 递归解析每个模块的依赖。
- 使用 loader 对模块进行转换(例如:
-
生成 Chunk:
- 根据入口和代码分割配置,将依赖图分成多个 Chunk(代码块)。
(3)输出阶段
- 将所有 Chunk 转换成文件(通常是
.js、.css、图片等)。 - 将文件输出到配置的
output.path目录。 - 在输出过程中,插件会执行额外操作(例如:
HtmlWebpackPlugin生成 HTML,CleanWebpackPlugin清理旧文件)。
2.3 核心概念
| 概念 | 作用 |
|---|---|
| Entry | 入口文件,webpack 从这里开始构建依赖图。 |
| Output | 配置打包后的文件输出路径和文件名。 |
| Loader | 用于转换非 JS 模块(如 CSS、图片、TypeScript)。 |
| Plugin | 用于执行打包过程中的额外任务(如生成 HTML、压缩代码)。 |
| Chunk | 打包过程中生成的代码块,可以按需加载。 |
| Bundle | 最终输出的文件,通常是一个或多个 JS 文件。 |
| Module | webpack 中的所有资源(JS、CSS、图片等)都被当作模块。 |
3. 原理示意图
[入口文件] index.js
↓
[解析依赖] 递归查找 import/require
↓
[Loader转换] ES6→ES5, Sass→CSS, 图片→Base64
↓
[构建依赖图] Dependency Graph
↓
[代码分割] 生成多个 Chunk
↓
[Plugin处理] 压缩、生成HTML、清理旧文件
↓
[输出文件] dist/main.js, dist/style.css, ...
4. 为什么 webpack 能处理各种资源
webpack 本身只能理解 JS 和 JSON,其他类型的文件需要通过 loader 转换:
- babel-loader:将 ES6+ 转成 ES5
- css-loader:解析 CSS 文件
- style-loader:将 CSS 注入到 HTML
<style>标签 - file-loader:处理图片、字体等静态资源
- ts-loader:处理 TypeScript
5. 插件的作用
插件可以在 webpack 构建的各个阶段介入,执行额外任务:
- HtmlWebpackPlugin:自动生成 HTML 文件,并引入打包后的 JS/CSS
- MiniCssExtractPlugin:将 CSS 提取成单独的文件
- TerserPlugin:压缩 JS 代码
- CleanWebpackPlugin:每次构建前清理输出目录
6. 总结
webpack 的原理可以概括为:
- 从入口文件开始,递归解析所有依赖。
- 使用 loader 将非 JS 资源转换成模块。
- 生成依赖图并分割成多个 Chunk。
- 通过插件优化和处理输出文件。
- 最终输出浏览器可识别的静态资源。