vue-cli 项目升级 webpack@4.x

vue-cli 项目升级 webpack@4.x 记录。

起因

打算自己写一个 Vue 组件库,通过造轮子的方式来寻找自己的技术盲区。

vue-cli 使用的 2.x 版本,同时使用 vuepress 来写使用文档,期间某些 webpack plugin 由于版本太低而报错,遂升级。升级之后新版本的 webpack plugin 又只能在 webpack@4.x 上使用,所以决定升级 webpack。本文介绍的是从 webpack3 到 webpack4 的升级过程。

替换安装包

  • 升级 nodejs

使用 webpack4 时,必须保证 Node.js 版本 >= 8.9.4,因为 webpack4 使用了大量的 ES6 语法,这些语法在 nodejs 新版 v8 中得到了原生支持

1
2
3
4
5
6
7
// package.json

"engines": {
+ "node": ">= 8.9.4",
- "node": ">= 6.0.0",
2"npm": ">= 3.0.0"
},
  • 升级 webpack 主要部件

包括 webpack、webpack-bundle-analyzer、webpack-dev-server、webpack-merge

:::warning
注意
webpack4 版本中 cli 工具分离成了  webpack  核心库 与  webpack-cli  命令行工具两个模块,需要使用  CLI,必须安装  webpack-cli  至项目中。
:::

升级的操作很简单,先删除,再安装即可。

1
2
// 卸载旧版本
npm uninstall -D webpack webpack-bundle-analyzer webpack-dev-server webpack-merge
1
2
// 安装新版本
npm install -D webpack webpack-cli webpack-bundle-analyzer webpack-dev-server webpack-merge
  • 升级 webpack 相关插件

包括 copy-webpack-plugin、css-loader、eslint-loader、file-loader、html-webpack-plugin、url-loader、friendly-errors-webpack-plugin、optimize-css-assets-webpack-plugin、uglifyjs-webpack-plugin

1
npm uninstall -D copy-webpack-plugin css-loader eslint-loader file-loader html-webpack-plugin url-loader  friendly-errors-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
1
npm install -D copy-webpack-plugin css-loader eslint-loader file-loader html-webpack-plugin url-loader  friendly-errors-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
  • 替换 webpack 相关插件

CSS 抽取插件 extract-text-webpack-plugin 替换为 mini-css-extract-plugin

1
npm uninstall -D extract-text-webpack-plugin
1
npm install -D mini-css-extract-plugin
  • 升级 vue-loader

由于 vue-loader 升级到版本 15 后,配置有较多的变化,稳妥起见,原作者只将 vue-loader 升级到 14.4.2。我在查询了相关文档之后,决定升级到最新版:

1
2
npm uninstall -D vue-loader
npm install -D vue-loader

修改配置文件

下面对配置文件的修改进行详细说明:

vue-loader

Vue Loader v15 需要配合一个 webpack 插件才能正确使用。在webpack.dev.conf.jswebpack.prod.conf.js两个文件里面分别添加:

1
2
3
4
5
6
7
+ const VueLoaderPlugin = require('vue-loader/lib/plugin')

const devWebpackConfig = merge(baseWebpackConfig, {
plugins: [
+ new VueLoaderPlugin()
2 ]
})

可参考:vue-loade 官网

webpack.base.conf.js

增加node:process.env.NODE_ENV即可

1
2
module.exports = {
+ mode: process.env.NODE_ENV,

utils.js

将 extract-text-webpack-plugin 替换为 mini-css-extract-plugin

1
2
3
4
5
6
7
8
9
10
11
12
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin")
- const ExtractTextPlugin = require('extract-text-webpack-plugin')

if (options.extract) {
+ return [MiniCssExtraPlugin.loader].concat(loaders)
- return ExtractTextPlugin.extract({
- use: loaders,
- fallback: 'vue-style-loader'
- })
} else {
return ['vue-style-loader'].concat(loaders)
}

webpack.prop.conf.js

该文件的配置项较为复杂

  • 将 ExtractTextPlugin 替换为 MiniCssExtraPlugin
1
2
3
4
5
6
7
8
9
10
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin")
- const ExtractTextPlugin = require('extract-text-webpack-plugin')

...
- new ExtractTextPlugin({
+ new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
}),
...
  • 删除 UglifyJsPlugin 配置项
1
2
3
4
5
6
7
8
9
10
11
- const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

- new UglifyJsPlugin({
- uglifyOptions: {
- compress: {
- warnings: false
- }
- },
- sourceMap: config.build.productionSourceMap,
- parallel: true
- })
  • 删除 CommonsChunkPlugin 配置项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- new webpack.optimize.CommonsChunkPlugin({
- name: 'vendor',
- minChunks (module) {
- return (
- module.resource &&
- /\.js$/.test(module.resource) &&
- module.resource.indexOf(
- path.join(__dirname, '../node_modules')
- ) === 0
- )
- }
- }),
- new webpack.optimize.CommonsChunkPlugin({
- name: 'manifest',
- minChunks: Infinity
- }),
- new webpack.optimize.CommonsChunkPlugin({
- name: 'app',
- async: 'vendor-async',
- children: true,
- minChunks: 3
- }),
...
  • 添加 optimization 配置项,生产环境打包优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
+ optimization: {
+ splitChunks: {
+ chunks: 'async',
+ minSize: 30000,
+ minChunks: 1,
+ maxAsyncRequests: 5,
+ maxInitialRequests: 3,
+ automaticNameDelimiter: '~',
+ name: true,
+ cacheGroups: {
+ vendors: {
+ test: /[\\/]node_modules[\\/]/,
+ priority: -10
+ },
+ default: {
+ minChunks: 2,
+ priority: -20,
+ reuseExistingChunk: true
+ }
+ }
+ },
+ runtimeChunk: { name: 'runtime' }
+ },

参考

  • 博客园 - 小火柴的蓝色理想
  • Vue Loader