大家好,我是一名普通的前端开发。
最近我把一个维护了两年的老项目从 Webpack 4 升级到了 Webpack 5。过程不算特别顺,但也算不上多难。今天就把我真实碰到的六个“坑”和对应的解决办法写下来,全是白话,希望能帮到正在升级的朋友。
为什么非要从 4 升到 5?
Webpack 5 打包更快、产物体积更小,长期缓存也更友好。如果你的项目还在 4 上跑,可以考虑升一下。
坑一:Node.js 核心模块不再自动补 polyfill
现象:
升级后启动报错,提示找不到 crypto、path、buffer 等模块。
原因:
Webpack 4 会自动给 Node.js 核心模块补 polyfill。Webpack 5 把这个功能移除了,因为前端代码本就不应该强依赖这些模块。
解决办法:
打开 webpack.config.js,找到 resolve.fallback 配置。
// webpack.config.js
module.exports = {
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
path: require.resolve('path-browserify'),
buffer: require.resolve('buffer/'),
}
}
}如果你的代码里没有用到这些模块,那就直接删掉对应的引用。建议优先检查依赖包,能升级依赖就升级,不行再加 fallback。
坑二:打包后 chunk 文件名变乱
现象:
打包出来的 JS 文件名从 vendor~main.xxxx.js 变成了 969.xxxx.js,完全看不懂。
原因:
Webpack 5 修改了模块 ID 的生成算法,默认使用 deterministic 模式,不再使用数字递增 ID。
解决办法:
不用慌,这个是正常行为。如果想保持可读性,可以在配置里指定文件名规则:
// webpack.config.js
module.exports = {
output: {
chunkFilename: '[name].[contenthash:8].js',
},
optimization: {
chunkIds: 'named', // 开发环境用
// 生产环境建议保持 'deterministic'
}
}生产环境建议保留 deterministic,因为这样可以保证长期缓存有效。
坑三:持久缓存导致热更新不生效
现象:
改了代码,页面却不更新。重启 Webpack 就好了,但过一会儿又出现。
原因:
Webpack 5 新增了持久化缓存(filesystem cache)。在某些情况下缓存数据变得不准确。
解决办法:
开发环境可以临时关闭 filesystem 缓存,或者每次启动前清理缓存目录。
// webpack.config.js
module.exports = {
cache: {
type: 'memory', // 开发环境用内存缓存
}
}如果你希望保留缓存但遇到更新问题,可以指定缓存版本:
cache: {
type: 'filesystem',
version: 'dev-v1',
}坑四:devServer 配置项大面积改名
现象:
devServer 启动时报各种未知配置项,比如 contentBase、watchContentBase、stats 等。
原因:
Webpack 5 对应的 webpack-dev-server 升级到了 v4,配置项全面改版,更贴近新版 Express。
解决办法:
对照下旧配置和新配置的映射关系:
旧配置 (Webpack 4) 新配置 (Webpack 5)
contentBase static.directory
watchContentBase static.watch
stats 移到根配置的 stats 字段
overlay client.overlay
示例:
// Webpack 4
devServer: {
contentBase: './dist',
watchContentBase: true,
stats: 'errors-only',
}
// Webpack 5
devServer: {
static: {
directory: './dist',
watch: true,
},
client: {
overlay: true,
},
}另外 hot 和 liveReload 默认已经开好,不用手动写。
坑五:打包后 chunk 缓存无法命中
现象:
每次部署后,用户的浏览器依然请求旧版本的 chunk,或者所有 chunk 的哈希值全变了。
原因:
Webpack 5 默认优化了模块合并,导致未修改的模块也可能因为依赖关系的变化而重新生成哈希。
解决办法:
开启 optimization.moduleIds 和 optimization.chunkIds 的 deterministic 模式(Webpack 5 默认已开启)。
同时建议把 runtimeChunk 单独抽出来:
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
},
}这样做可以保证业务代码变动时,第三方库的 chunk 哈希不会跟着变。
坑六:部分 Loader 和 Plugin 不兼容
现象:
升级后报错,提示某个 loader 或 plugin 不支持 Webpack 5。
原因:
Webpack 5 改动了 Plugin API 和部分 Loader 的调用时机。
解决办法:
我遇到的主要有这些:
html-webpack-plugin 升级到 5.5.0 以上
mini-css-extract-plugin 升级到 2.6.0 以上
webpack-dev-server 升级到 4.0.0 以上
terser-webpack-plugin 升级到 5.0.0 以上
升级命令示例:
npm install webpack@5 webpack-cli@5 webpack-dev-server@4 --save-dev
npm install html-webpack-plugin@5 mini-css-extract-plugin@2 --save-dev如果不确定哪些不兼容,可以先删除 node_modules 和 package-lock.json,然后重新安装。
写在最后
Webpack 5 升级并不算特别复杂,只要把这六个问题提前看清楚,基本一天内就能把中小项目搞定。
升级前最好先备份配置,或者用 webpack-merge 新建一个 webpack.config.prod.v5.js 慢慢试。先把开发环境跑通,再切生产环境。遇到报错不要慌,报错信息在 Webpack 5 里已经写得很清楚了,按提示改就行。
如果大家遇到上面没提到的问题,欢迎交流。
更多经验分享链接我放在下边了:
https://segmentfault.com/a/1190000047775647
https://segmentfault.com/a/1190000047769687
https://segmentfault.com/a/1190000047762004
https://segmentfault.com/a/1190000047752393
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。