vue-cli 3 多页应用与分包

前言

自从vue-cli推出了3.0版本之后就一直在研究使用,手头的新项目都上了3.0,2.0的老项目也切了几个。

相较于2.0版本Webpack配置一大堆,3.0封装了绝大部分的Webpack相关配置并暴露了一些可配置的参数接口(比如vue.config.js文件)。

3.0上手确实容易多了✈️

封装之后上手是简单了,但是自定义也更加困难了。

需求

老项目有两个需求,分页分包缩减

分页

“分页”是业务上的需求,因为项目有两大业务类别,所以需要分包实现。参照官网的pages配置即可。

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 = {
pages: {
index: {
// page 的入口
entry: 'src/index/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
// 当使用只有入口的字符串格式时,
// 模板会被推导为 `public/subpage.html`
// 并且如果找不到的话,就回退到 `public/index.html`。
// 输出文件名会被推导为 `subpage.html`。
subpage: 'src/subpage/main.js'
}
}

分包缩减

这个由用户反馈而来。因为项目中了用了一些UI库(通过WebpackBundleAnalyzer观察得),打包后的vendors包特别大,1M多,gzip后也有3、400k大小,直接影响首屏的加载,可以考虑的方法是将UI库分包。

看了下Vue-cli 3的文档,没有相关分包加载的直接设置项,但是可以自定义Webpack的配置。

chainWebpack——结合webpack-chain的链式操作API,直接修改项目Webpack配置。

configureWebpack——将定义的配置对象merge到Webpack配置中。

chainWebpack

直接操作Webpack配置,比如加入包分析工具WebpackBundleAnalyzer、设置alias等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const isAnalyze = true; // 是否启用bundleAnalyzer

// ...

module.defaults = {
// ...
chainWebpack: config => {
config.resolve.alias // 设置alias
.set('Less', resolve('src/less'));
if (isAnalyze) { // 设置bundle-analyzer
config
.plugin('bundle-analyzer')
.use(WebpackBundleAnalyzer);
}
// ...
},
// ...
}

configureWebpack

可以设置optimization.splitChunks.cacheGroups配置分包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 以拆element-ui为例
module.exports = {
// ...
configureWebpack: {
optimization: {
splitChunks: {
cacheGroups: {
theme: {
name: 'chunk-theme',
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
chunks: 'all',
priority: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
},
// ...
}

分包实现

SPA

如果是SPA,只需要通过vue-cli 3的默认配置和上面的configureWebpack配置即可实现。

Sample配置如文末仓库。

MPA

如果是MPA,就没那么简单了。由于每个入口只需要自己的js和公共chunks、UI-chunk,所以默认的pages配置已经不能满足需求了(html-webpack-plugin的一些参数vue-cli3并不支持配置,需要自己修改webpack配置实现)。

所以这边的解决方案是:

  • configureWebpack的内容不变,依然是ui分包的配置;
  • 不使用vue.config.js中的pages,在chainWebpack中自行加入entryHtmlWebpackPlugin

具体实现就不写了,Sample配置见文末仓库。

注意点

在实现的时候遇到了一些问题,这边记录一下。

1. TypeError: Cannot read property 'tapAsync' of undefined

google后得到结果是”html-webpack-plugin”不能放在”preload-webpack-plugin”的后面。link

配置chainWebpack时添加html-webpack-plugin时使用.before('xxx')方法即可。

2. 配置了分页后,dev环境不能访问每个分页怎么办

webpack-dev-server有一个参数配置historyApiFallback,可以实现dev模式下的分页访问。

3. index.html中的BASE_URL未定义

默认情况下,vue-cli会给process.env注入几个属性值,其中就有BASE_URL,值为'/'

但是当进行MPA配置时是我们自写的插件配置,所以必须要将BASE_URL写入到htmlWebpackPlugin的templateParameters中。(即使vue.config.js中配置了baseUrl)

Sample

见仓库suyi91/vue-cli3-samples