优化Vue项目首屏加载

921 阅读2分钟

因为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;