vue首屏加载优化总结及整理

 

页面加载性能是一个老生常谈的问题,但是却异常重要,尤其在访问量大的商业软件中。但是有很多开发者在开发过程中压根就没有考虑过这个问题。大家在开发业务代码的过程中,也就忽略了这个增加工作量,也不会带来什么直观的工作内容。


写在前面,这里以vue框架为例,基于vue-cli3的开发方式

首先,使用webpack分析工具,查看当前项目的依赖,分析依赖及打包情况,对症下药

安装插件

npm i webpack-bundle-analyzer -D

在vue.config.js中,添加如下配置:

chainWebpack: (config)=>{
    /* 添加分析工具*/
    if (process.env.NODE_ENV === 'production') {
      if (process.env.npm_config_report) {
        config
          .plugin('webpack-bundle-analyzer')
          .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
          .end()
        config.plugins.delete('prefetch')
      }
    }

    ...
  }

执行命令

npm run build --report

执行成功后,浏览器会打开一个窗口,显示当前依赖的大小及各打包文件情况

vue首屏加载优化总结及整理

结合自己的项目情况,分析依赖的引入及打包情况,有以下几点优化方式

第一,路由懒加载。

查看打包目录中,js文件夹下的chunk-哈希值的文件为采用懒加载形式时生成的文件,一个路由会生成一个文件。

const home= () => import('@/pages/home/index.vue')

第二,使用CDN引入第三方依赖。

比如,直接引入ehcarts会发现占打包文件较大的空间,如果项目没有特殊要求,可以采用CDN的方式引入;其他诸如axios、vue、lodash等都可以采用这种方式。

  • 在index.html中引入CDN资源
...
  <body>
    <div id="app">
    </div>
    <!-- built files will be auto injected -->
    <script src="//cdn.bootcss.com/echarts/4.2.1/echarts.simple.min.js"></script>
  </body>
  ...
  • 修改vue.config.js配置文件
module.exports = {
    configureWebpack: {
      externals: {
        'echarts': 'echarts' // 配置使用CDN
      }
    }
   }

externals中的key是用于import,value表示的在全局中访问到该对象,就是window.echarts

在vue中使用echarts的时候无需 import echarts,可直接使用

第三,按需加载第三方类库

比如,项目中使用了 lodash 库,如果不是大量使用里面的方法的话,可以这样引入

import _cloneDeep from 'lodash/difference' // 或者 const _cloneDeep = require('lodash/difference')
const o = _cloneDeep ({a: 1, b: 2}) 

也可以借助第三方插件的形式,lodash-webpack-plugin和babel-plugin-lodash。

在使用中还是采用原有的 import _ from 'lodash'方式,只是借助插件,在打包时webpack会根据使用的方法按需打包

先安装依赖

npm install lodash-webpack-plugin babel-plugin-lodash -D

上述插件可能部分已经存在于项目中,可以根据实际删除

接着修改 vue.config.js


const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");

module.exports = {
  configureWebpack: config => {
     if (process.env.NODE_ENV === 'production') {
        return{
           plugins: [
              new LodashModuleReplacementPlugin(), //优化lodash
           ]
        }
     }
  }
};

附:使用 IgnorePlugin 插件优化 moment.js


const webpack = require('webpack');

module.exports = {
  configureWebpack: config => {
     if (process.env.NODE_ENV === 'production') {
        return{
           plugins: [
              new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // 忽略/moment/locale下的所有文件
           ]
        }
     }
  }
};

按需引入 element-ui,参见官方文档即可,其他组件库类似

注:如果是按需一次性在main.js中引入,虽然比全部引入要小一些,但是也会一定程度上影响首次加载,这个看项目而行吧。

按需引入后element-ui小了很多,不过看到文章开头的图上显眼的 table.js后想到, table组件只有后台管理页面用到了,不需要全局注册,所以我们删除 main.js中 Table和 TablColumn的引用,并在后台组件中局部注册。

这里处理的思路就是,将按需引入处理到极致。如果是对首屏要求很高,可以采用这种方式,哪里用到哪里才引用,这其实也是平时开发中的一种良好习惯。

chunk.venders.js 。如果是文件为第三方依赖的打包后文件,在做完这些优化之后,会发现这个文件有显现的减小。

第四,打包时去掉sourceMap文件

修改 vue.config.js 配置

module.exports = {
  productionSourceMap: false
}

第五,将静态资源使用cdn加载

将项目中的静态资源js css等放在oss服务器或者其他地方,减小服务器压力

第六,开启 gzip压缩

我在项目中启用压缩后,文件大小减少了70%以上,优化效果十分明显。

下图是在简单做了部分优化之后的加载过程(优化开始时忘了截图),耗时8s以上。服务器端配置以 nginx 为例

如果 Nginx 服务器开启 gzip,会将静态资源在服务端进行压缩,压缩包传输给浏览器后,浏览器再进行解压使用,这大大提高了网络传输的效率,尤其对 js,css 这类文本的压缩,效果很明显。

客户端

安装依赖

npm i -D compression-webpack-plugin

修改 vue.config.js 配置

const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
 ...
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      return {
        plugins: [
          new CompressionPlugin({
            test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png/, // 需要压缩的文件类型
            threshold: 10240, // 归档需要进行压缩的文件大小最小值,这里是10K以上的进行压缩
            deleteOriginalAssets: false // 是否删除原文件
          })
        ]
      }
    }
  }
}

打包后,查看js文件

vue首屏加载优化总结及整理

可以看到所有文件都被压缩了三分之二以上

在服务器我们也要做相应的配置

# 开启|关闭 gzip。
gzip on|off;
# 文件大于指定 size 才压缩,以 kb 为单位。
gzip_min_length 10;
# 压缩级别,1-9,值越大压缩比越大,但更加占用 CPU,且压缩效率越来越低。
gzip_comp_level 2;
# 压缩的文件类型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
# 开启后如果能找到 .gz 文件,直接返回该文件,不会启用服务端压缩。
gzip_static on|off
# 是否添加响应头 Vary: Accept-Encoding 建议开启。
gzip_vary on;
# 请求压缩的缓冲区数量和大小,以 4k 为单位,32 为倍数。
gzip_buffers 32 4K;

注:遇到服务端开启gzip后,并没有生效的问题,发现是nginx配置压缩文件类型时 application/x-javascript,如果是这样的写法则并不会生效。

JavaScript的MIME类型通常为“application/x-javascript”, 非IE的浏览器认“application/javascript”,

所以在上述配置中 application/javascript 和 application/x-javascript 并用,可以解决该问题。

然后重启nginx服务

systemctl restart nginx.service

当在请求中出现如下标识,即开启成功

vue首屏加载优化总结及整理

再对比一下资源加载时间

vue首屏加载优化总结及整理

vue首屏加载优化总结及整理

前者为启用压缩前,后者为压缩后,时间从8.33s减少到了2.44s,效率提高了70%以上

第七,冗余代码

打包文件 app.哈希.js 中为所有vue文件打包的集合。

基于此,把项目中的冗余代码,注释的多余代码删除一通后,你会发现文件会变小。

可能人就是这样,在项目中觉得多几行css 多几个标签觉得不会对页面产生什么影响,但是如果做一通优化之后看到了‘数字性’的减少,才会思考编写高性能代码对加载性能的影响。

第八,浏览器缓存

浏览器缓存可以分为强缓存和协商缓存,根据实际应用场景来选择缓存方式或者结合使用。一般来讲一些基本不会变化的静态资源文件可以设置强缓存,更新频繁的文件不要设置缓存。而启用缓存的好处在于,在某个时间段内可以减少发送请求的数量,从而使页面响应更快,也就有更好的页面体验。

基本原理:浏览器缓存分强缓存和协商缓存,他们是将网络资源存储在本地,等待下次请求该资源时,如果命中就不需要到服务器重新请求该资源,直接在本地读取该资源。

  • 强缓存:在web服务器返回的响应中添加Expires和Cache-Control Header
  • 协商缓存:通过【Last-Modified, If-Modified-Since】和【ETag, If-None-Match】两对Header分别管理

关于缓存的详细介绍,推荐一篇文章,时空隧道

好啦,文章提到的优化方式基本就是这些,当然优化也不至于此,还有网络加载优化、页面渲染优化(动画、重排、重绘等)、浏览器文件缓存等等。如果有更好的优化方式欢迎评论。

写在最后,页面优化本身是一件很抽象的工作,但是我们却可以通过平时的编码规范来促成更可靠的页面。优化的过程也是一个见仁见智的过程,要结合实际项目实际分析。优化的过程也会引发我们对于编码时的一些思考,原来这样写对页面加载会更友好,不知不觉中也能促进编写高可用的能力。

 

上一篇:javascript-在Lodash.js / Underscore.js中,如何为每个元素添加索引?


下一篇:在vue-cli中引入lodash.js并使用