前言
webpack5 现在的最新版本已经是5.5
了,相对来说比较稳定,但是截止到2021.08.19,React
的相关脚手架工具create-react-app
最近一次更新仅仅是在14天前,commit message 是 :『webpack5
』。
所以即使webpack5
本身比较稳定了,但主流框架的一些工具也可能最近才做了适配或者还没有做适配,也就是说本文的一些问题不一定具有长效性,在你升级的过程中可能不会遇到本文提到的问题,也可能遇到本文没有提到的问题。
综上本文仅供参考。
前期调研
Node
的版本要在10.13.0
及以上- 如果你是
webpack3
,请先将他升级到webpack4
准备工作
首先打开webpack
给出的官方升级指南:
webpack: to V5 from V4: webpack.js.org/migrate/5/
可以发现里头已然讲的非常具体了,我们首先要做以下几步:
1. 首先将webpack4
升级到version 4
以下的最新版本,目前最新的版本是4.46.0
2. 升级所有的loader
以及plugin
到适配webpack5
的版本
这里要注意的是有些loader
以及plugin
的@latest
版本并不是适配webpack5
的版本,而@next
版本才是,所以升级的时候建议核对一下该loader
/plugin
的npm
首页,查看是否有@next
的版本,并安装正确的版本.
!注意: 当你的npm
版本在7
以上的时候,在安装最新的loader
/plugin
过程中很有可能会报出如下错误:
解决方法在报错中也给出了,在安装命令后应加上--legacy-peer-deps
,所以你的安装命令应该如下:
npm i ${yourPluginName@yourPluginVersion} --legacy-peer-deps
出现这个错误的原因是npm
在7
以上的版本中,默认安装peerDependencies
插播:简单介绍一下peerDependencies
:
我们常见的是dependencies
和devDependencies
,前者是依赖,后者是开发时安装的依赖,而peerDependencies
(如下图所示)相对来说比较陌生
我们可以用一个例子来简单了解一下peerDependencies
,如下:
如果dependency1
和dependency2
都在Dependency
里声明了dependency3
,并且依赖的版本不同,那么他们的依赖树应该是这样:
root/node_modules/
|
+- dependency1/node_modules/
| |
| +- dependency3 v1.0/
|
|
+- dependency2/node_modules/
|
+- dependency3 v2.0/
这样项目会安装两个版本的dependency3
。然而,如果声明在了peerDependencies
里,依赖树将会是这样:
root/node_modules/
|
+- dependency1/
|
+- dependency2/
|
+- dependency3 v1.0/
也就是说,peerDependencies
里所需要的依赖会统一安装在根目录下,而不会安装多次
所以,回到上面那副图,你会发现peerDependencies
里依赖的版本往往是一个范围,而不是某个特定的版本号
npm
在7
以前的版本不会首先根据peerDependencies
安装依赖,所以不会报错,而7
以上的版本会则会抛出错误
在升级loader
/plugin
过程中,这两者一般都是基于webpack
开发的,与根目录webpack
版本不兼容,所以抛出这个错误(例如最新的plugin
要求的webpack
版本是"^5.0.0"
,而咱们根目录的是"4.x"
)
加入--legacy-peer-deps
后就告诉npm
每个module
安装各自版本的第三方包,安装可以顺利进行,等升级完成后,我们再重新npm install
一遍,也可以减少依赖的下载和安装
3. 如果使用了webpack-cli
将其升级到最新版本
4. build 你的项目,尽量保证没有错误报出 (此时版本还是4.x
)
5. 如果使用了以下配置或plugin
,更改其写法
optimization.hashedModuleIds: true
→optimization.moduleIds: 'hashed'
optimization.namedChunks: true
→optimization.chunkIds: 'named'
optimization.namedModules: true
→optimization.moduleIds: 'named'
NamedModulesPlugin
→optimization.moduleIds: 'named'
NamedChunksPlugin
→optimization.chunkIds: 'named'
HashedModuleIdsPlugin
→optimization.moduleIds: 'hashed'
optimization.noEmitOnErrors: false
→optimization.emitOnErrors: true
optimization.occurrenceOrder: true
→optimization: { chunkIds: 'total-size', moduleIds: 'size' }
optimization.splitChunks.cacheGroups.vendors
→optimization.splitChunks.cacheGroups.defaultVendors
Compilation.entries
→Compilation.entryDependencies
serve
→serve
被DevServer
替代 (一般会安装webpack-dev-server
,所以这个一般不用改)Rule.query
(webpack3
以来就弃用了) →Rule.options
/UseEntry.options
安装webpack5
npm install webpack@latest
(可能你还是要用到 --legacy-peer-deps
命令)
生态对齐+踩坑记录
1. webpack-dev-server
需要升级
webpack-dev-server
需要升级到4.x
版本,也就是@next
版本,虽然其gitHub的更新记录表明在3.10
以上的版本就已经做了webpack5
的兼容,但是在我的项目里并不是适用。各位可以自己试一下,如果3.10
可以跑起来就最好,但如果要升级到4.x
版本,就要注意,配置项写法有很多更改,具体详情请看:
2. create-react-app
相关报错
TypeError: message.split is not a function. in node_modules\react-dev-utils\formatWebpackMessages.js
这个error
存在了很久了,具体可参考这个链接:
React
官方直到14天前的那一次把脚手架更新到next
版本才修复了这个问题,所以安装了最新的react-dev-utils
(再次提醒,是@next
版本)就可以解决这个问题,然而你会碰到另外的问题,如下:
can not resolve react-dev-utils/WatchMissingNodeModulesPlugin
以及can not resolve react-dev-utils/typescriptFormatter
原因也很简单,打开react-dev-utils
,最新版本的react-dev-utils
删除了这俩函数(typescriptFormatter
可能是在更早的版本删除的)
解决办法就是将两者移除即可,这两者并没有改名,最新版本react-dev-utils
要么将这些移除的函数功能内嵌进了其他函数,要么就是被其他loader
替代,要么就是webpack5
自带了这些功能
3. 更改相关webpack.config.js
的node: {}
如果你的webpack.config.js
有类似代码,你需要将他们移到resolve.fallback
before
node: {
fs: 'empty',
},
after
resolve: {
fallback: false,
},
4. webpack5
取消了polyfill
这是一个比较好解决的问题,当你跑项目的时候webpack5
会做出对应的提示,同样,你需要在resolve.fallback
里添加相关代码,类似这样:
fallback: {
"http": require.resolve("stream-http"),
"https": require.resolve("https-browserify"),
"zlib": require.resolve("browserify-zlib"),
"assert": require.resolve("assert/"),
"buffer": require.resolve("buffer/"),
"stream": require.resolve("stream-browserify"),
"os": require.resolve("os-browserify/browser")
}
添加完成后再把所需的第三方包自行安装一下即可
5. 更换optimize-css-assets-webpack-plugin
在optimize-css-assets-webpack-plugin
的gitHub首页明确指出在webpack5
以后推荐使用官方的css-minimizer-webpack-plugin
webpack5
新特性
1. 自带cache
在webpack5
以前,做cache
可能需要的是第三方的loader
对开销比较大的模块做缓存,但是到了webpack5
,其自带了cache
,用户可以通过如下简单的配置来做缓存:
// webpack.config.js\
module.exports = {
...,
cache: {
type: 'filesystem',
// 可选
buildDependencies: {
config: [__filename], // 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效(官方建议为[__filename]即可,可以及时更新相关依赖)
},
name: '', // 可以配置以name为隔离,不同的判断条件输出不同的缓存文件,如生成PC或mobile不同的配置缓存
...,
},
}
注意,这里只有type
是必填的,有两个选项memory
和filesystem
,如果使用了memory
,其他的cache
配置选项将会失效。以上只是cache
的某些配置,全部的详情请看
-
⚠️注意⚠️
很多项目使用
webpack
是通过node
模式,也就是会有compiler
const compiler = webpack(config);
请检查你的
bulid.js
文件,如果是使用了compiler
,务必加上compiler.close(() => {})
,不无法正确输出:(github.com/webpack/web…)
2. 内置静态资源构建能力 —— Asset Modules
- raw-loader:允许将文件处理成一个字符串导入
- file-loader:将文件打包导到输出目录,并在 import 的时候返回一个文件的 URI
- url-loader:当文件大小达到一定要求的时候,可以将其处理成 base64 的 URIS ,内置 file-loader
由于webpack
只打包js
文件,所以在使用过程中,我们常常用以上几个loader
来处理静态资源,然而在webpack5
里同样自带了这些功能,大致如下:
module: {
rules: [
// ...
{
resourceQuery: /raw/,
type: 'asset/source',
}
]
},
更改type
代表不同的loader
,详情可看 webpack.js.org/guides/asse… 以及 dev.to/smelukov/we…
webpack5
还有很多新功能,例如支持Top Level Async
,内置web worker
等等,但这些与升级过程有关,我的项目中也没有用到,就不展开说了,希望各位升级顺利。