一、Webpack 在做什么

Webpack 是一个模块打包器:把项目里所有资源(JS、CSS、图片、字体)当作模块,通过 loader 处理、plugin 增强,最终打包成浏览器能直接加载的静态文件。

二、四大核心概念

entry:入口

1
2
3
4
5
6
7
8
9
// webpack.config.js
module.exports = {
entry: './src/main.js',
// 多页面应用:多入口
entry: {
home: './src/home.js',
admin: './src/admin.js'
}
}

output:出口

1
2
3
4
5
6
7
8
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
// [name] 对应 entry 的 key,[contenthash] 内容变了文件名就变(缓存利器)
filename: 'js/[name].[contenthash:8].js',
clean: true // 每次构建先清空 dist
}
}

loader:处理非 JS 资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {
module: {
rules: [
// 处理 JS/JSX(含 TS)
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader'
},
// 处理 CSS + 兼容前缀
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
// 处理图片(小于 limit 转 base64 内联)
{
test: /\.(png|jpg|jpeg|svg)$/,
type: 'asset',
parser: { dataUrlCondition: { maxSize: 8 * 1024 } }
}
]
}
}

注意 use 数组是从右往左执行的(css-loader 先解析,style-loader 再注入)。

plugin:做 loader 做不到的事

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
plugins: [
// 自动生成 index.html 并注入打包产物
new HtmlWebpackPlugin({
template: './public/index.html'
}),
// 把 CSS 抽成独立文件(生产环境)
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css'
})
]
}

三、开发模式与生产模式

用环境变量区分配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// webpack.config.js
const isProd = process.env.NODE_ENV === 'production'

module.exports = {
mode: isProd ? 'production' : 'development',
devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',

devServer: {
port: 8080,
hot: true,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},

optimization: {
minimize: isProd // 生产压缩
}
}
1
2
3
4
5
6
7
// package.json
{
"scripts": {
"dev": "webpack serve --mode development",
"build": "NODE_ENV=production webpack --mode production"
}
}

四、代码分割:cacheGroups

公共依赖(react、lodash 等)单独拆 chunk,利用浏览器缓存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
// 三方库独立 chunk
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
// 被多个页面引用的公共代码
common: {
name: 'common',
minChunks: 2,
chunks: 'all'
}
}
}
}
}

配合动态 import 的懒加载:

1
2
// 路由懒加载,页面代码单独 chunk
const Admin = () => import('./pages/Admin')

五、持久化缓存:构建提速关键

Webpack 5 内置持久化缓存,二次构建时间大幅下降:

1
2
3
4
5
6
7
8
module.exports = {
cache: {
type: 'filesystem', // 默认开启,缓存写到 node_modules/.cache
buildDependencies: {
config: [__filename] // 配置变更时自动失效缓存
}
}
}

配合 moduleIds: 'deterministic'(Webpack 5 默认),模块 id 稳定,改代码不会让所有 chunk 的 hash 全变。

六、性能分析

1
npm install -D webpack-bundle-analyzer
1
2
3
4
5
6
7
8
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
plugins: [
// 构建后自动打开体积分析图
...(process.env.ANALYZE ? [new BundleAnalyzerPlugin()] : [])
]
}
1
ANALYZE=true npm run build

看分析图定位体积大户:换用体积更小的库(dayjs 替代 moment)→ 按需引入 → 拆 chunk → 懒加载。

常见坑

  1. 图片路径 404:publicPath 没配或配错,output.publicPath: '/' 是常见修复;
  2. HMR 不生效:确认 devServer.hot: true 且入口引用了热更新入口;
  3. 构建内存溢出:大项目 --max-old-space-size 调 Node 内存,或开启持久化缓存;
  4. contenthash 全变:检查是否用了 moduleIds: 'named'(开发默认),生产要用 deterministic。

总结

Webpack 5 的掌握路径:四大概念(entry/output/loader/plugin)→ 开发/生产双模式 → splitChunks 分包 + 懒加载 → 持久化缓存提速 → 分析插件瘦身。虽然新项目多用 Vite,但维护老项目、做深度构建定制时,Webpack 的知识仍然值钱。