webpack3 升级 4 采坑记

公司的项目,最早是用 ES6 写的,直接手写 webpack1 进行打包的。由于是 jsp 的页面,还做了单独的页面压缩,资源 hash 处理。后续也跟上了一些升级脚步,把webpack 逐步升级到 2,之后又是 3。现在看来也算是先见之明。

在后续业务中,逐步使用了 vue,使用 vue 主要是考虑到能够通过 cdn 等形式直接引入项目,省去了 webpack 的配置工作。现在同一个项目,后续我决定采用 react 进行开发,对原有项目进行了 3 次重构,终于把老代码独立到一个文件夹了,未来 react 的新代码可以在单独的文件夹下开发。最终发包时候合并在一起。

对于 react 我还是比较积极的,版本上从 16.5 直接更新到了 16.6。为了后续方便,也就筹划着把 webpack 升级到 4。

webpack 升级

webpack 主包升级到 4之后,主要有一点,需要单独安装 webpack-cli 了。

1
yarn add -D webpack-cli

安装完毕之后,直接启动,果不然报错。

extract-text-webpack-plugin

由于是夜里升级,当时没有相关记录。大致报错是 hooks 错误。

这个处理 css 的插件,一直没有更新主版本,所以默认版本不能兼容 webpack4,需要安装 next 版本。

1
yarn add -D extract-text-webpack-plugin@next

webpack 配置

webpack.optimize.CommonsChunkPlugin 已经移除了,需要换成 optimization.splitChunks

1
2
3
4
5
6
7
8
9
{
optimization: {
splitChunks: {
chunks: 'all',
minChunks: 3,
name: 'commons'
}
}
}

因为我们是手动往 jsp 页面插入资源文件,所以不方便用智能拆包。而且为了兼容之前的方案,就统一打包到 commons.js 中了。

移除不再使用的东西

uglifyjs-webpack-plugin 不在需要了,新版webpack 配置文件中,加入生产模式,自动压缩代码

1
2
3
{
mode: 'production'
}

同样的,不需要再设置 ENV 了:

1
2
3
4
5
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})

还有一个不知道用途的插件,也被提示要求移除:

1
new webpack.optimize.AggressiveMergingPlugin()

babel 系列

之前 babel 的包,是这样子风格的 babel-core,新包已经变成 @babel/core 了。改成了私有前缀下的子包形式了。

所以,需要重新安装包:

1
yarn add -D @babel/core @babel/preset-env @babel/preset-react

由于我用了 react 的一个实验性质语法,原本用的 stage-0,新版 babel 不再支持 stage-0 这种包了。所以需要改为手动安装。

babel 提供了一个工具, npx babel-update,但是这个工具没能成功修复 package.json 文件,仅仅在控制台回显了那些行需要删除,需要新增那些行。

presets 写法也有一点变化,不能简写了。最后 webpack 配置文件中规则如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
query: {
presets: [
['@babel/preset-env', { 'modules': false }],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}]
}

自动 polyfill

最后,我发现了了一个好东西。浏览器访问资源,自动根据 useragent 返回需要的 polyfill。

项目地址:https://polyfill.io

这样所有资源都不需要关系 polyfill 了。

后续的开发思考

所有的重量级资源,均采用 cdn 等形式引入,不再进行 webpack 打包了。这样自己打包速度快,也省去了引用资源增加导致 commons.js 变化。

配置大致如下:

1
2
3
4
5
6
{
externals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}

当然如果是 lodash 之类的,可以按功能进行 tree shake 的,还是可以打包到 commons.js 中的。

–END–