因为vue项目是SPA单页面项目,所以往往项目的资源会在首屏加载,这就导致投产上线后第一次加载白屏很久。这里主要写我在实践中使用的三种优化点。
以 vue-cli 搭建的项目为例,使用vue+vue-router+vuex,ajax请求使用axios,UI框架使用element-ui。
区分开发、生产环境使用CDN资源
如果 vue、vue-router、vuex、axios、element-ui
这些项目固定的依赖都在 main.js
中引入,最后编译出来的 vendor.js
会变得很大。我们要将这些依赖从 vendor.js 中分离出来,使用CDN资源引入压缩版js。
但是使用了vue和vuex压缩版之后,我们就无法在开发的时候使用vue-devtools
Chrome调试工具,所以我们要区分生产和开发环境配置。
1. 修改 public/index.html
通过 htmlwebpackplugin
动态注入脚本和样式,index.html如下:
(非vue-cli项目修改根目录下的index.html)
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png">
<title>Vue optimization</title>
<!-- 加载 cdn css -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- 加载 cdn js -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</body>
</html>
2. 修改 vue.config.js 配置
// vue.config.js
// ..
const isProd = process.env.NODE_ENV === 'production'
const assetsCDN = {
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
axios: 'axios',
'element-ui': 'ELEMENT'
},
css: ['https://cdn.jsdelivr.net/npm/element-ui@2.13.2/lib/theme-chalk/index.css'],
js: [
'//cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js',
'//cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js',
'//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js',
'//cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js',
'//cdn.jsdelivr.net/npm/element-ui@2.13.2/lib/element-ui.common.min.js'
]
}
module.exports = {
configureWebpack: {
// 如果是生产环境,新增externals
externals: isProd ? assetsCDN.externals : {}
},
chainWebpack: config => {
// 如果是生产环境,将css、js的cdn地址赋值给html-webpack-plugin插件
if (isProd) {
config.plugin('html').tap(args => {
args[0].cdn = assetsCDN
return args
})
}
}
}
路由懒加载
如果路由对应的组件都是直接import引入到router.js中,那么编译出来的app.js
会非常大,影响首屏加载,但很多页面不一定会被点击进入。
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
// src/router/index.js
// 非懒加载
import Home from '@/components/Home/Home'
// 懒加载写法一
const Login = resolve => require(['@/components/Home/Login'], resolve)
// 懒加载写法二
const Post = () => import('components/Home/Post')
export default new Router({
routes: [
{path:'*',redirect:'/home'},
{
path: '/',
redirect:'/home',
},
{
path: '/home',
name: 'Home',
component: Home,
alias:'/123'
},
{
path: '/Login',
name: 'Login',
component: Login,
},
{
path: '/Post',
name: 'Post',
component: Post
}
],
})
Nginx 开启 gzip
修改nginx配置文件 nginx.conf
:
# $gzip_ratio计算请求的压缩率,$body_bytes_sent请求体大小
log_format main '$remote_addr - $remote_user [$time_local] "$host" - "$request" '
'$gzip_ratio - $body_bytes_sent - $request_time';
access_log logs/access.log main;
# 开启gzip
gzip off;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 1;
# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";
# 设置压缩所需要的缓冲区大小
gzip_buffers 32 4k;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.0;