Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。它会分析你的项目结构,找到 JavaScript 模块及其他资源(如 CSS、图片),将其打包为一个或多个 bundle 文件。
第一章:为什么要学 Webpack?
在现代前端开发中,我们会使用模块化、Sass、TypeScript、图片、字体等资源。但浏览器并不天然支持这些格式,因此我们需要工具将它们打包、转换成浏览器能识别的文件格式。Webpack 就是这样一个强大的前端构建工具。
什么是模块化?
模块化指的是将代码拆成功能单一的文件,每个文件内部维护自己的作用域与功能。
我们通过 import 和 export 实现模块之间的引用与暴露:
// utils.js
export function add(a, b) {
return a + b;
}
// index.js
import { add } from './utils';
console.log(add(1, 2));
什么是 ES 和 ESM?
ES:即 ECMAScript,JavaScript 的标准。
ESM(ES Modules):即 ES6 引入的模块系统,通过 import 和 export 语法进行模块化。
项目为什么需要打包?
-
浏览器不原生支持 ES6 模块、SCSS、图片等资源类型
-
我们写了很多模块,浏览器加载过多资源会影响性能
-
希望统一管理依赖、进行压缩混淆,提高加载速度
Webpack 到底解决了什么问题?
-
把多个模块合并成一个或多个 bundle
-
支持各种资源(CSS、图片、字体、JSON)导入
-
提供开发服务器、热更新、压缩、分包、Tree Shaking 等高级功能
Webpack 与 Vite 的区别?
| 对比点 | Webpack | Vite |
|---|---|---|
| 构建原理 | 打包时构建全部模块 | 按需即时构建(基于 ESM) |
| 启动速度 | 较慢(需要打包) | 快速(利用原生 ES 模块) |
| 热更新速度 | 一般 | 更快 |
| 构建配置 | 更灵活、生态庞大 | 更现代、内置功能多 |
| 插件体系 | 成熟,插件数量丰富 | 稍逊,但生态快速发展中 |
第二章:Webpack 的核心组成结构
Entry(入口)
Webpack 构建的起点,告诉它从哪里开始分析依赖。
entry: './src/index.js'
Output(输出)
Webpack 打包后的输出文件路径与文件名。
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
Loader(模块转换器)
Webpack 默认只能识别 JS 文件。Loader 让 Webpack 能够处理非 JS 文件,如 CSS、图片等,把它们转成 JS 模块。
Plugin(插件)
增强 Webpack 功能的机制,例如自动生成 HTML 文件、提取 CSS、压缩优化代码等。
DevServer(开发服务器)
Webpack 内建的本地开发服务器,支持热更新(HMR)、自动刷新、快速预览。
SourceMap
映射压缩后的代码到源码位置,方便调试。
Mode(模式)
指定当前构建环境:
development:开发模式,包含调试信息,不压缩代码。
production:生产模式,自动压缩优化。
第三章:搭建第一个 Webpack 项目(对比 Vite)
创建项目结构
webpack-demo/
├─ src/
│ └─ index.js
├─ dist/
│ └─ index.html
├─ webpack.config.js
└─ package.json
初始化并安装依赖
npm init -y
npm install webpack webpack-cli --save-dev
编写 webpack.config.js 配置
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true
},
mode: 'development'
};
执行构建命令
npx webpack
和 Vite 的对比
Webpack 会将 src 中的模块打包到 dist/bundle.js 中。
| 操作 | Webpack | Vite |
|---|---|---|
| 安装包体积 | 较大(多个核心包) | 较小(vite 本身即可) |
| 启动开发 | npx webpack --watch | npx vite |
| 运行效果 | 先构建 bundle 再运行 | 即时构建,按需编译 |
Webpack 强调构建逻辑完整掌控,而 Vite 更偏向快速开发体验。
第四章:支持 CSS 样式文件
未配置时会报错
默认 Webpack 不识别 .css 文件,会提示 Module parse failed。
安装处理样式的 loade
npm install css-loader style-loader --save-dev
配置规则
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
loader 功能解释
-
css-loader:让 JS 能 import .css 文件
-
style-loader:将样式插入到
Vite 中则天然支持 CSS,无需配置。
第五章:支持 ES6+ 高级 JS
浏览器不支持新语法怎么办?
使用 Babel 将 ES6+ 转换成兼容的 ES5 代码。
安装 Babel 相关依赖
npm install babel-loader @babel/core @babel/preset-env --save-dev
添加 Babel 配置文件 .babelrc
{
"presets": ["@babel/preset-env"]
}
修改 webpack.config.js 中的 module.rules
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
这样 Babel 就可以帮助你把如箭头函数、let/const 等语法编译成老浏览器能识别的代码。
和 Vite 对比
Vite 默认基于 esbuild 编译,速度更快,配置更少。 Webpack 配合 Babel 功能更强,但配置较繁琐。
第六章:Webpack 5 的 HMR(热模块替换)
什么是 HMR?
HMR 即热模块替换,是一种在应用运行时,替换、添加或删除模块的技术,而无需整个页面刷新。它能极大提升开发体验,快速反馈修改结果。
HMR 的作用
提升开发效率:代码改动后,立即更新页面内容,不刷新整个页面。
保留应用状态:避免刷新后丢失当前应用状态(如表单输入、页面滚动等)。
加速调试:快速定位问题,减少等待。
Webpack 5 中 HMR 的使用方式
-
默认支持:Webpack 5 对开发模式(mode: ‘development’)默认开启 HMR。
-
配合 devServer 使用:通常配合 webpack-dev-server,配置如下:
module.exports = {
mode: 'development',
devServer: {
hot: true, // 开启 HMR
},
};
- 代码中使用 HMR API(可选):
如果你想针对某个模块单独控制热更新,可以写:
if (module.hot) {
module.hot.accept('./moduleA.js', function () {
// 模块 moduleA 更新时执行的逻辑,比如重新渲染
});
}
HMR 工作原理简述
-
Webpack 监听文件变化,重新编译对应模块。
-
生成更新的模块代码,并通过 WebSocket 发送给浏览器。
-
浏览器接收模块更新,调用对应的 module.hot.accept 处理更新逻辑。
-
页面局部刷新模块内容,避免全页面刷新。
Webpack HMR 和 Vite HMR 的区别
| 方面 | Webpack HMR | Vite HMR |
|---|---|---|
| 架构原理 | 传统打包构建,文件改动后重新编译模块,发送更新 | 利用原生 ES 模块导入(ESM),直接按需加载单个模块,改动只更新改动的模块 |
| 构建方式 | 先构建整个依赖图,打包成一个或多个 bundle | 开发阶段不打包,利用浏览器原生 ESM 逐个请求文件,实现即时加载 |
| 启动速度 | 慢,需完整构建依赖图和打包 | 超快,几乎零启动,直接启动开发服务器 |
| 热更新响应速度 | 较慢,文件变动触发重新打包相关模块,更新量大 | 极快,只发送变动模块路径,浏览器直接重新请求对应模块 |
| 实现复杂度 | 复杂,需要处理模块依赖关系、更新边界等 | 简单,基于浏览器 ESM 原生支持,无需额外打包 |
| 生态成熟度 | 非常成熟,插件、loader 丰富 | 新兴,生态逐渐丰富,但不如 Webpack 广泛 |
| 使用体验 | HMR 能力强,适合大型项目,但启动和更新慢 | HMR 非常快速,体验更流畅,适合现代前端框架 |
| 生产环境打包 | 依赖 Webpack 打包 | 依赖 Rollup 进行生产打包 |
| 对旧浏览器支持 | 兼容性好 | 依赖现代浏览器支持 ES 模块,旧浏览器需要 polyfill |
第七章:Webpack 5 的 Tree Shaking(摇树优化)
什么是 Tree Shaking?
Tree Shaking 是一种“摇掉没用代码”的优化技术。通过静态分析,Webpack 能检测代码中未被使用(dead code)的部分,并在打包时剔除它们,减小最终包体积。
# Tree Shaking 的实现条件
-
必须使用 ES Module(ESM):即 import 和 export 语法,Webpack 静态分析才能确定依赖关系。
-
开启 production 模式:Webpack 默认在 mode: ‘production’ 下开启 Tree Shaking。
-
代码要写成纯函数或无副作用,便于静态分析。
Webpack 5 配置与用法
-
mode: ‘production’ 自动开启:
-
Tree Shaking
-
压缩(TerserPlugin)
-
-
在 package.json 里声明 “sideEffects” 字段,告诉 Webpack 哪些文件或模块有副作用,哪些可以安全摇掉:
{
"sideEffects": false
}
或者针对某些文件:
{
"sideEffects": ["*.css", "*.scss"]
}
Tree Shaking 的限制
-
只能针对 ESM 模块有效,CommonJS(require)无法有效摇树。
-
动态导入或副作用代码不易被优化。
-
某些语法或写法会阻止摇树,比如动态属性访问。
Tree Shaking 原理简述
-
Webpack 会基于 ESM 语法构建依赖图。
-
标记哪些 export 被使用,哪些没用。
-
在压缩阶段(由 Terser 插件处理)删除无用代码。
第八章:支持 React 项目开发
创建项目结构
webpack-react-demo/
├─ public/
│ └─ index.html
├─ src/
│ ├─ App.jsx
│ └─ index.js
├─ webpack.config.js
└─ package.json
安装依赖
npm install react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server \
@babel/core @babel/preset-env @babel/preset-react babel-loader \
html-webpack-plugin css-loader style-loader
配置文件 webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
devServer: {
static: './dist',
hot: true,
open: true
},
mode: 'development'
};
JSX 与样式支持说明
-
@babel/preset-react 处理 JSX 语法
-
css-loader 与 style-loader 处理样式文件
-
HtmlWebpackPlugin 自动生成 index.html 并插入 script 标签
启动开发服务器
npx webpack serve
你现在已经可以通过 Webpack 自定义打包一个完整的 React 应用了。
2430

被折叠的 条评论
为什么被折叠?



