☀️ 初衷:关于vue-cli3配置参考,google出来的结果大多不理想。所以自己收集捣鼓总结vue-cli3-config-reference。
👉 vue-cli在2019-11-27发布了新版本v4.1.0,后续会新开vue-cli4的分支,记录总结config-reference。
0️⃣ 以下例子均基于@vue/cli v3.11.0
$ vue --version
3.11.0
- ✔️ 取消eslint错误显示在浏览器中
- ✔️ 启用构建速度分析工具
- ✔️ 启用bundle分析工具
- ✔️ lodash按需引入
- ✔️ moment按需引入语言包
- ✔️ 启用静态压缩
- ✔️ 启用js和css的sourceMap
- ✔️ DllPlugin配置
- ✔️ 添加别名alias
- ✔️ 去除console.log
- ✔️ 配置CSS Modules
- ✔️ 向所有 Less 样式传入共享的全局变量
- ✔️ 向所有 Scss 样式传入共享的全局变量
- ✔️ 向所有 Sass 样式传入共享的全局变量
- ✔️ 向所有 Stylus 样式传入共享的全局变量
- ✔️ 配置proxy代理解决跨域
- ✔️ 解决第三方包的IE11兼容
- ✔️ 使用web worker
- ✔️ dart-sass替换node-sass
- ✔️ 开启CDN加速
- ✔️ 缩小打包作用域
- ✔️ echarts按需加载
- ✔️ 预加载、vue-meat-info
运行vue create
新建的项目,默认的lintOnSave:'error'
,lint 错误不仅仅输入到命令行,也直接显示在浏览器中。设置lintOnSave:true
即可。
- true:
eslint-loader
会将 lint 错误输出为编译警告。默认情况下,警告仅仅会被输出到命令行,且不会使得编译失败。 - 'error':这会强制
eslint-loader
将 lint 错误输出为编译错误,同时也意味着 lint 错误将会导致编译失败。 - false:取消eslint检查。
// vue.config.js
module.exports = {
lintOnSave: true
}
tip:修改配置重启后,如无效果,需要Ctrl+s保存文件,触发检查。
$ yarn add speed-measure-webpack-plugin -D
配置vue.config.js,实例化一下SpeedMeasurePlugin,包住configureWebpack就可以啦。
// vue.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
// 可传options参数,参考https://www.npmjs.com/package/speed-measure-webpack-plugin
const smp = new SpeedMeasurePlugin()
module.exports = {
configureWebpack: smp.wrap({
plugins: []
})
}
跑一下npm run build
,效果就出来啦!!!
SMP ⏱
General output time took 1 min, 18.38 secs
SMP ⏱ Plugins
CompressionPlugin took 0.196 secs
SMP ⏱ Loaders
modules with no loaders took 55.73 secs
module count = 2293
vuetify-loader, and
cache-loader, and
vue-loader, and
eslint-loader took 45.29 secs
module count = 383
cache-loader, and
thread-loader, and
babel-loader, and
vuetify-loader, and
cache-loader, and
vue-loader took 40.36 secs
...
$ vue add webpack-bundle-analyzer
不需要配置任何script,在build的时候加上--report即可。在开发环境中,默认自动打开http://127.0.0.1:8888
,查看分析报告,由于 webpack-bundle-analyzer
需要物理文件来计算已解析和gzip压缩的大小,因此只能使用stat大小;如果运行npm run build --report
,dist目录下会生成report.html,默认自动打开该文件。
关闭自动打开分析文件功能:
// vue.config.js
module.exports = {
pluginOptions: {
webpackBundleAnalyzer: {
openAnalyzer: false
}
}
}
参考:vue-cli-plugin-webpack-bundle-analyzer
- 只安装并引入你需要的lodash包
$ yarn remove lodash
$ yarn add lodash.clonedeep -S
//在需要的地方引入
import cloneDeep from "lodash.clonedeep";
- 使用babel-plugin-lodash
$ yarn add babel-plugin-lodash -D
修改.babelrc文件:
{
"plugin":["lodash"]
}
- 使用lodash-es
webpack的tree-shaking
只对es6模块生效,而lodash本身是commonjs模块,所以import { cloneDeep } from "lodash"
是实现不了按需加载的,但是它有一个lodash-es版本,用的就是es6模块。
$ yarn add lodash-es -S
import { cloneDeep } from 'lodash-es'
// 相当于 import cloneDeep from "lodash.clonedeep";
moment支持123种语言,但它又不能事先知道你需要哪一种语言包,保险起见,打包的时候会把所有的语言包打包进去。默认是en,所以en这个语言包是肯定会自动打包进去的。
// 国际化示例
moment.locale('zh-cn')
moment().format('LLL') // 2019年11月19日早上8点46分
moment.locale('en')
moment().format('LLL') // November 19, 2019 8:48 AM
webpack-bundle-analyzer分析图如下:
- 按需引入语言包
// vue.config.js,下面只引入中国和中国香港的语言包,可根据自身需求引入
const webpack = require('webpack')
module.exports = {
chainWebpack: config => {
config
.plugin('ignore')
.use(new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /(zh-cn)|(zh-hk)$/))
return config
}
}
- 忽略所有语言包,并使用import单独引入特定语言包
// vue.config.js
const webpack = require('webpack');
module.exports = {
chainWebpack: config => {
config
.plugin('ignorePlugin')
.use(webpack.IgnorePlugin, [{ // 引入的文件路径匹配/^\.\/locale$/,则会忽略这个文件, 也就不会被打包进去
resourceRegExp: /^\.\/locale$/, // 忽略所有语言包,所有locale功能失效,功能缺失那肯定是不允许的。在main.js单独引入语言包即可
contextRegExp: /moment$/,
}]);
}
}
//main.js
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
console.log(moment().format('LLL')) // 2019年11月19日早上8点46分
- 使用date-fns或dayjs替代
名字 | 大小(gzip) | 支持Tree-shaking | api方法数 | 时区支持 | 支持语言数 |
---|---|---|---|---|---|
Moment.js | 329K(69.6K) | No | 高 | 非常好 | 123 |
date-fns | 78.4k(13.4k) without tree-shaking | YES | 高 | 还不支持 | 32 |
dayjs | 6.5k(2.6k) without plugins | No | 中 | 还不支持 | 23 |
启用压缩分为动态压缩和静态压缩。
- 动态压缩是由nginx对每个请求进行压缩, 缺点是压缩过程占用cpu的资源,压缩比越高cpu占用越高,不需要修改webpack配置,修改nginx.conf文件即可。
- 静态压缩:使用compression-webpack-plugin对打包文件进行压缩,会生成对应的.gz文件。nginx发现存在对应的.gz文件后,会使用该压缩文件,就不需要自己压缩一遍了。
yarn add compression-webpack-plugin -D
// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.mode = 'production'
return {
plugins: [new CompressionPlugin({
test: /\.js$|\.html$|\.css/,
threshold: 10240,//大于10kb的就进行压缩
deleteOriginalAssets: false //是否删除源文件
})]
}
}
}
}
配置nginx,在http、server、location下加以下代码:
# 开启静态压缩
gzip_static on;
#识别http的协议版本。由于早期的一些浏览器或者http客户端,可能不支持gzip自解压,用户就会看到乱码,所以做一些判断还是有必要的
gzip_http_version 1.1;
# 启用压缩,如果header包含expired no-cache no-store private auth其中一种
gzip_proxied expired no-cache no-store private auth;
# 不启用压缩的条件,IE6对Gzip不友好,所以不压缩
gzip_disable "MSIE [1-6]\.";
# 和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
gzip_vary on;
如果使用的是node和express,在需要启用静态压缩的中间件前注册一个中间价即可:
const compression = require('compression')
app.use(compression())
如需启用开发环境的静态压缩,配置devServer即可:
// vue.config.js
module.exports = {
devServer:{
compress: true
}
}
参考:webpack官网 devServer.compress
为CSS开启sourceMap后,在检索元素查看css时,可以精确知道来自于哪一个文件,点击文件名,可以到达Sources面板查看该文件。
// vue.config.js
module.exports = {
css: {
sourceMap: false
}
}
生产环境中,vue-cli是默认开启的,为Javascript开启sourceMap后,构建时会生成.map文件,可以帮助你在生产环境调试代码,当然,开启sourceMap后就会影响项目的构建速度。
module.exports = {
productionSourceMap: false, // 生产环境禁用
configureWebpack: {
devtool: false // 开发环境禁用
}
}
参考:
配置 js.sourceMap
vue-cli文档#productionsourcemap
更多devtool配置
vue 开发过程中,保存一次就会编译一次。利用DllPlugin,把一些库(一般不会去改动)提取出来,只编译修改的js文件,加快编译的速度。
yarn add webpack-cli@^3.2.3 add-asset-html-webpack-plugin@^3.1.3 clean-webpack-plugin@^3.0.0 -D
在项目根目录下新建 webpack.dll.conf.js:
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// dll文件存放的目录
const dllPath = 'public/vendor'
module.exports = {
entry: {
// 需要提取的库文件
vendor: ['vue', 'vue-router', 'vuex', 'axios', 'element-ui']
},
output: {
path: path.join(__dirname, dllPath),
filename: '[name].dll.js',
// vendor.dll.js中暴露出的全局变量名
// 保持与 webpack.DllPlugin 中名称一致
library: '[name]_[hash]'
},
plugins: [
// 清除之前的dll文件
new CleanWebpackPlugin(),
// 设置环境变量
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: 'production'
}
}),
// manifest.json 描述动态链接库包含了哪些内容
new webpack.DllPlugin({
path: path.join(__dirname, dllPath, '[name]-manifest.json'),
// 保持与 output.library 中名称一致
name: '[name]_[hash]',
context: process.cwd()
})
]
}
生成 dll:添加dll选项,并运行yarn run dll
// package.json
"scripts": {
"dll": "webpack -p --progress --config ./webpack.dll.conf.js"
},
为了节约编译的时间,这时间我们需要告诉 webpack 公共库文件已经编译好了,减少 webpack 对公共库的编译时间。
// vue.config.js
const path = require('path')
const webpack = require('webpack')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
module.exports = {
...
configureWebpack: {
plugins: [
new webpack.DllReferencePlugin({
context: process.cwd(),
manifest: require('./public/vendor/vendor-manifest.json')
}),
// 将 dll 注入到 生成的 html 模板中
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, './public/vendor/*.js'),// dll文件位置
publicPath: './vendor',// dll 引用路径
outputPath: './vendor'// dll最终输出的目录
})
]
}
}
疑惑:添加DllPlugin后,每次保存后重新编译时间确实减少了,从平均3.6s降到2.4s。但是运行yarn run serve
,编译时间几乎一样。后续还得探索探索...
- 配置configureWebpack
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
configureWebpack: {
resolve: {
alias: {
'@components': resolve('src/components'),
'@': resolve('src')
}
}
}
}
- 配置chainWebpack
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
chainWebpack:config => {
config.resolve.alias
.set('@components',resolve('src/components'))
.set('@',resolve('src'))
}
}
- 使用 babel-plugin-transform-remove-console 插件
yarn add babel-plugin-transform-remove-console -D
添加babel配置:
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);
const plugins = [];
if (IS_PROD) plugins.push("transform-remove-console")
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins
}
- 使用uglifyjs-webpack-plugin
yarn add uglifyjs-webpack-plugin -D
添加vue.config.js:
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);
module.exports = {
configureWebpack: config => {
if (IS_PROD) {
const plugins = []
plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_console: true, //注释console.log
drop_debugger: false,
pure_funcs: ['console.log'] //移除console
}
},
sourceMap: false,
parallel: true
})
)
config.plugins = [...config.plugins, ...plugins]
}
}
}
@vue/cli已经集成了CSS Modules,可以通过 <style module>
达到开箱即用。但如果想去掉文件名中的 .module或自定义生成 CSS Modules 模块的类名,还需要配置vue.config.js。
// vue.config.js
module.exports = {
css: {
requireModuleExtension: false, // 去掉文件名中的 .module
loaderOptions: {
css: {
modules: {
// 自定义类名,name:CSS Modules所在的文件名;local:原定的类名
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
}
}
}
注意:在将css-loader升级到版本3之后,yarn run serve
之后会报错,认为localIdentName是无效的选项。是因为localIdentName选项需要嵌套在modules选项中。update yarn packages & update get_style_rule to handle [email protected]
Module build failed (from ./node_modules/css-loader/dist/cjs.js):
ValidationError: Invalid options object. CSS Loader has been initialised using an options object that does n
ot match the API schema.
- options has an unknown property 'localIdentName'. These properties are valid:
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }
at validate (C:\Users\chenweihuan\Desktop\demo\vue-demo1\node_modules\css-loader\node_modules\schema-uti
ls\dist\validate.js:85:11)
at Object.loader (C:\Users\chenweihuan\Desktop\demo\vue-demo1\node_modules\css-loader\dist\index.js:34:2
8)
推荐阅读:深入理解vue的scoped和module原理
参考: vue-cli#css-modules
使用less需要安装less和less-loader:
yarn add less less-loader -D
// 示例安装的版本:"less": "^3.10.3", "less-loader": "^5.0.0"
- 配置less.globalVars
module.exports = {
css: {
loaderOptions: {
less: {
globalVars: {
primary: 'blue'
}
}
}
}
}
less全局变量的使用:
<style lang="less">
.color {
color: @primary;
}
</style>
// global.less
@primary:red;
- 利用style-resources-loader,简单粗暴(墙裂推荐):
vue add style-resources-loader
安装时会让你选择css的语言,选择less后,@vue/cli还会在vue.config.js自动生成一段样例代码,添加上路径即可:
// vue.config.js
const path = require('path')
module.exports = {
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [path.resolve(__dirname, "src/styles/global.less")]
}
}
}
参考:
vue-cli-plugin-style-resources-loader
向预处理器 Loader 传递选项
使用scss需要安装sass-loader和node-sass:
yarn add sass-loader node-sass -D
// 示例安装的版本:"sass-loader": "^8.0.0", "node-sass": "^4.13.0"
- 配置vue.config.js:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
scss: {
// 假设在src/styles有两个文件:global.scss和app.scss
// @/ 是 src/ 的别名
// `scss` 语法会要求语句结尾必须有分号,不然会报错
prependData: `
@import "~@/styles/global.scss";
@import "~@/styles/app.scss";
`
}
}
}
}
scss全局变量的使用:
// app.scss
$color: blue;
<!-- App.vue -->
<style lang="scss">
.blue{
color: $color;
}
</style>
- 使用style-resources-loader即可,简单粗暴:
vue add style-resources-loader
// vue.config.js
const path = require('path')
module.exports = {
pluginOptions: {
'style-resources-loader': {
preProcessor: 'scss',
patterns: [path.resolve(__dirname,'src/styles/app.scss')]
}
}
}
使用style-resources-loader即可,简单粗暴:
vue add style-resources-loader
// vue.config.js
const path = require('path')
module.exports = {
pluginOptions: {
'style-resources-loader': {
preProcessor: 'sass',
patterns: [path.resolve(__dirname,'src/styles/app.sass')]
}
}
}
sass的全局变量使用:
// app.sass
$primary: green;
<!-- App.vue -->
<style lang="sass">
.container
color: $primary;
</style>
使用stylus需要安装stylus和stylus-loader:
yarn add stylus stylus-loader -D
// 示例安装的版本:"stylus": "^0.54.7", "stylus-loader": "^3.0.2"
- 配置vue.config.js:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
stylus: {
// 假设在src/styles有两个文件:mixins.styl和app.styl
import: [
'~@/styles/mixins.styl',
'~@/styles/app.styl'
]
}
}
}
}
stylus全局变量的使用:
// app.styl
font = 20px;
<style lang="stylus">
.font {
font-size: font;
}
</style>
- 使用style-resources-loader即可,简单粗暴:
vue add style-resources-loader
// vue.config.js
const path = require('path')
module.exports = {
pluginOptions: {
'style-resources-loader': {
preProcessor: 'stylus',
patterns: [path.resolve(__dirname,'src/styles/mixins.styl')]
}
}
}
如果你的前端应用和后端 API 服务器没有运行在同一个主机上,会出现跨域问题,你需要在开发环境下将 API 请求代理到 API 服务器。
// vue.config.js
module.exports = {
devServer: {
open: false, // 是否打开浏览器
host: "0.0.0.0", // 可让你的应用跑在不同的机器上,使用localhost或IP访问
proxy: {
// 仅代理/api和/api2开头的接口
"/(api|api2)": {
target:
"http://...:4000" // 目标代理接口地址
}
}
}
};
使用vue create
构建项目后,已经能解决本地开发的IE11兼容问题,但并不能解决第三方库的IE11兼容问题。@babel/polyfill
即将被废弃,使用core-js
和regenerator-runtime
代替。
- 全局引入
yarn add core-js regenerator-runtime -S
// main.js
import "core-js/stable";
import "regenerator-runtime/runtime";
// .babelrc
module.exports = {
presets: [
['@vue/cli-plugin-babel/preset', { useBuiltIns: 'entry' }]
]
}
- 按需引入
默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在transpileDependencies这个选项中列出来。假如是因为引入vuex-pathify包的问题,配置如下:
// vue.config.js
module.exports = {
transpileDependencies: [
'vuex-pathify'
]
}
参考:
core-js @babel/polyfill
vue-cli文档 - transpileDependencies
在vue里使用web worker,下面是一个构建部门树的核心代码:
// tree.worker.js
const nest = (items, code = 0, link = 'parentCode') => { // code就是老爸的code,大型认爹现场
return items
.filter(v => v[link] === code)
.map(v => ({ ...v, children: nest(items, v.code) }))
}
self.addEventListener('message', (e) => { // self代表子线程自身,即子线程的全局对象。
let { data } = e
let { type, root } = data
if (type === 'BUILD') {
const tree = nest(root)
self.postMessage({
type,
payload: {
root: tree
}
})
}
}, false)
// App.vue
import treeWorker from './tree.worker.js'
let worker = new treeWorker()
export default {
mounted () {
worker = new treeWorker()
worker.addEventListener('message', this.handlerMessage)
// 清除worker监听
this.$once('hook:beforeDestroy',()=>{
worker.removeEventListener('message',this.handlerMessage)
worker.terminate()
})
// 请求后台数据拿到原始部门data
setTimeout(() => {
worker.postMessage({
type: 'BUILD',
root: data
})
})
},
methods: {
handlerMessage(e){
console.log(e)
}
}
}
安装worker-loader,否则会报错"export 'default' (imported as 'treeWorker') was not found in './tree.worker'
:
yarn add worker-loader -D
修改vue.config.js配置:
// vue.config.js
module.exports = {
chainWebpack: config => {
// 解决重新刷新页面或者重开启devServe都只取缓存,xx.work.js不更新的问题。
// 具体讨论参考issues:https://github.com/webpack-contrib/worker-loader/issues/195
config.module.rule('js').exclude.add(/\.worker\.js$/)
// 使用worker-loader编译.worker.js文件
config.module
.rule('worker')
.test(/\.worker\.js$/)
.use('worker-loader')
.loader('worker-loader')
.options({
name: '[name].worker.js'
})
.end()
}
}
解决 yarn
时,卡死在node-sass这里。
yarn remove node-sass
yarn add sass -S
修改vue.config.js配置:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
sass: {
implementation: require('sass')
}
}
}
}
参考:
https://dev.to/helleworld_/integrating-dart-node-sass-in-vuejs-4o39
不用区分测试环境还是生产环境,统一都用cdn即可。修改index.html:
<!DOCTYPE html>
<html>
<head>
...
<!-- element还需引入css文件 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="https://unpkg.com/[email protected]/dist/vue.runtime.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuex.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.min.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</body>
</html>
修改vue.config.js配置:
// vue.config.js
module.exports = {
configureWebpack: {
externals: {
vue: "Vue",
vuex: "Vuex",
"vue-router": "VueRouter",
"element-ui": "ELEMENT"
}
}
};
打包后抛到服务器上,打开开发者工具的network,如果看到http请求cdn,那么就代表配置成功了。但有可能会出现未知BUG,谨慎使用。
参考:开启CDN加速
// vue.config.js
module.exports = {
configureWebpack: {
resolve: {
// 合理使用别名
alias: {
'@': path.resolve(__dirname, './src/components')
},
// 指定在这些目录里寻找引用的库,提高搜索效率
modules: [
path.resolve(__dirname, './node_modules')
],
// 尽可能减少后缀尝试的可能性,默认值为:[".js", ".json"]
extensions: ['.js'],
// 只采用 main 字段作为入口文件描述字段
// 减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段
mainFields: ['main']
}
}
}
- require(官方方案)
// 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts');
// 引入柱状图
require('echarts/lib/chart/bar');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 绘制图表
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
});
- babel-plugin-equire
添加babel-plugin-equire插件:
yarn add babel-plugin-equire -S
编辑 .babelrc 文件:
{
"plugins": [
"equire"
]
}
新建文件 echarts.js :
const echarts = equire([
'bar',
'title',
'tooltip'
])
export default echarts
在需要用到 echarts 的地方引入 echarts.js 文件:
import echarts from './echarts'
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('app'));
// 绘制图表
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
});
- @vue/cli
vue add prerender-spa
接下来跟着命令行操作即可。
// 哪一个路由需要进行预加载配置,逗号隔开,且只适用于history路由模式
? Which routes to pre-render? (separate with comma) (only with Vue Router history mode) /,/home
// 是否使用事件触发快照
? Use a render event to trigger the snapshot? Yes
? Use a headless browser to render the application? Yes
// 是否只在生产环境开启预渲染
? Only use prerendering for production builds? Yes
到这里就已经完成了,该添加的配置@vue/cli已经做完。跑一下npm run build
,在dist里生成对应路由单独的HTML文件就是生效了(我这里是多生成一个文件 home.html)
- prerender-spa-plugin
npm install prerender-spa-plugin --save
配置vue.config.js:
// vue.config.js
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
configureWebpack: () => {
if (process.env.NODE_ENV !== 'production') return;
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/', '/home',],
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: false,
// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'x-app-rendered'
})
})
]
};
},
}
配置main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
router,
render: h => h(App),
mounted: () => document.dispatchEvent(new Event("x-app-rendered")),
}).$mount('#app')
预渲染的作用是什么?
如果你调研服务器端渲染 (SSR) 只是用来改善少数营销页面(例如 /, /about, /contact 等)的 SEO,那么你可能需要预渲染。无需使用 web 服务器实时动态编译 HTML(SSR),而是使用预渲染方式,在构建时简单地生成针对特定路由的静态 HTML 文件。优点是设置预渲染更简单,并可以将你的前端作为一个完全静态的站点。
既然是为了SEO,那么还需要注意Meta信息的变化,vue-meta-info是个很好的抉择。
npm install vue-meta-info --save
全局引入 vue-meta-info:
import Vue from 'vue'
import MetaInfo from 'vue-meta-info'
Vue.use(MetaInfo)
组件内静态使用 metaInfo:
<script>
export default {
metaInfo: {
title: 'My Example App', // set a title
meta: [{ // set meta
name: 'keyWords',
content: 'My Example App'
}]
link: [{ // set link
rel: 'asstes',
href: 'https://assets-cdn.github.com/'
}]
}
}
</script>
如果你的 title 或者 meta 是异步加载的,也可以的,参考处理 Vue 单页面 Meta SEO的另一种思路
参考:
vue-cli-plugin-prerender-spa
Vue-Cli3.0怎么使用预渲染怎么配置prerender-spa-plugin