【腾讯云前端性能优化大赛】亚军方案-前端首屏优化实践

事实上, 只有10%-20%的最终用户响应时间是发在从Web服务器获取HTML文档并传送到浏览器中的。 如果希望能够有效地减少页面的响应时间,就必须关注剩余80%-90%的最终用户体验。 –Steve Souders


大家好,前端性能优化是一个非常重要的问题,首屏时间长短,直接影响到用户的体验与留存。本文介绍一下优化过程的心路和历程。最终从2000ms优化到148ms。

一、项目技术栈

框架:Vue2

打包工具:webpack

二、优化方法

1.代码压缩

gzip压缩可以节省50%-70%的网络开销

浏览器支持的压缩类型可以通过network的Accept-Encoding: gzip, deflate来查看。支持deflate的浏览器也支持gzip,但很多浏览器支持gzip却不支持deflate,因此gzip是最理想的压缩方法。

代码语言:txt
复制
// webpack中配置如下:
const CompressionWebpackPlugin = require('compression-webpack-plugin')

const productionGzipExtensions = ["js", "css", "html"]

if (config.build.productionGzip) {
const CompressionWebpackPlugin = require("compression-webpack-plugin");
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: new RegExp(
"\.(" + config.build.productionGzipExtensions.join("|") + ")$"
      ),
threshold: 10240,
minRatio: 0.8
    })
  );
}

代码语言:txt
复制
// nginx 中配置
gzip on; # 开启Gzip
gzip_static on; # 开启静态文件压缩
gzip_min_length 1k; # 不压缩临界值,大于1K的才压缩
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss; # 进行压缩的文件类型
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6].";

开启gzip一定要前后单同时操作才有效!!!

开启gzip

F12打开浏览器控制台-network,成功!

2.配置sourceMap

代码语言:txt
复制
productionSourceMap: false,

关掉sourceMap

3.使用CDN内容分发网络

index.html文件中通过环境来判断是否引入cdn文件,webpack通过环境判断是否使用cdn引入文件的全局变量。

只需在刚刚配置gzip的代码加上一段代码即可:

代码语言:txt
复制
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require("compression-webpack-plugin");
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: new RegExp(
"\.(" + config.build.productionGzipExtensions.join("|") + ")$"
      ),
threshold: 10240,
minRatio: 0.8
    })
  );
// 配置externals就是当使用CDN进入的js文件在当前项目中可以引用
// 比如在开发环境引入的vue是import Vue from 'vue', 这个大写的Vue就是对应的下面的大写的Vue
webpackConfig.externals = {
vue: "Vue",
"vue-router": "VueRouter",
axios: "axios"
  };
}

在html中引入这段代码,使用EJS语法判断是否为生产环境,引入:

代码语言:txt
复制
  <body>
<div id="app"></div>
<% if (process.env.NODE_ENV === 'production') { %>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
<% } %>
</body>

同时去掉所有的import和Vue.use()

代码语言:txt
复制
// import Vue from 'vue'
// import Router from "vue-router";
// Vue.use(Router);

F12打开浏览器控制台-network,引入cdn成功!

引入cdn

4.将图片打包上传至七牛云

有些图片实在是过大,影响了资源加载的时间,故将其打包上传至七牛云或者阿里云oss对象存储中,这样页面中用不到图片的时候,就不加载,减轻了首屏资源加载的压力。

5.去除首屏不需要的依赖

可以看到,首屏大文件是elementUI,elementUI采用部分引入,故最后只有48kb,其实是lodash,但排查发现,全局只使用了一次lodash,故不在app.js中全局引入,在使用的地方引入即可。

依赖分析

去除lodash后如下,首页所需加载的依赖减小至82kb左右,是可以接受的范围。

去除lodash后

6.其他

  • 压缩图片,推荐工具:https://tinypng.com/
  • 路由懒加载:需要在router里配置,这样触发某条路由,再去加载对应的资源,减少首屏压力
  • 优化后端接口:首屏的接口如果有特别耗时的,那么就需要去优化后端了,比如本文对首页的热点数据使用了redis缓存,速度更快。
  • elementUI按需加载(这里有个存疑,我的element按需加载后是80kb,但也采用过cdn方案,目前两者性能相差无异)
  • SSR?没有去实践,正值期末考试,以后再尝试吧~


最后打包分析,可以看见依赖已经非常小了,网站肉眼可见的快了~

优秀成绩

三、总结

因为本项目是将vue、vuex、vue-router、axios、element-ui都放到了bootCDN上,所以资源加载取决于cdn的快慢,所以成绩一直不是很稳定,各位大佬轻喷。

服务器是位于上海的阿里云服务器,前后端单体部署。

榜中的最好成绩是cdn比较快的时候,146ms,平时大部分稳定在200-400ms,还是取决于cdn网速和到服务器的距离。

目前网站经过一系列优化后,速度不如巅峰时期了,我也改不回去了......

非常曲折的优化过程