前言:以前一直认为性能优化很遥远,也很复杂,但当今天尝试过后,发现也并不是触不可及
一、 背景
代码语言:javascript复制上周出现了一个严重的线上bug,用户打开网页时直接白屏无法使用,然后发现有一个JS文件加载出错了,状态码虽然时`200 OK`,但是控制台打印了`net::ERR_CONTENT_LENGTH_MISMATCH`以及那个JS文件名,字面意思理解就是HTTP请求头中的Content-length字段缺失,接下来就是要知道为什么会出现这个问题,好在这个问题还比较常见,一下就找到了:
由于文件过大(这个JS文件确实相当大,达到了1.4MB),Nginx会尝试从proxy_temp文件夹中获取文件,但nginx没有proxy_temp文件夹的权限。
这个问题是真的很匪夷所思,但是线上使用要紧,紧急将文件夹的权限更改了一下先保证服务正常运行,那么为了从源头上解决问题,自然就开始尝试压缩打包体积。
复制代码
二、 优化思路
* 废话
老实说一开始并没有什么想法,唯一的想法是尽量按需引入依赖,所以先安装了webpack-bundle-analyzer
插件:
npm i -D webpack-bundle-analyzer
然后在vue.config.js中配置插件:
代码语言:javascript复制const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}
复制代码
这样就得到了打包后的整体大小的可视化界面:
然后我就先尝试开始对图中的cryto-js进行优化,将其使用的地方改为按需引入(先对这个进行改造主要是两点: 1. 本身体积也不算小 2. 使用的地方较少),优化后结果如下:
从51KB缩小到16KB,效果还是很明显的,但是终归只是杯水车薪,何况其他的要改造起来难度要大不少,特别是那个iview.js,一开始用的全局引入,现在一百多个Component里都有用到,改起来感觉相当折磨。
gzip压缩-压缩包体积
对按需引入绝望的我,开始在网上搜索其他压缩体积的方法,发现很多文章第一个讲的都是gzip压缩——服务器在回传文件前先对文件进行压缩(此时HTTP头部中会包含有Content-encoding: gzip
),浏览器拿到文件后再对其解压; 主要操作是需要更改服务器的配置,如我们项目使用的Nginx,就需要再Nginx的配置文件(/etc/nginx/nginx.conf)中添加如下内容:
# 一下内容需要放在http或者server中
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
复制代码
然后reload一下:nginx -s reload
,之后刷新网页(注意禁用缓存)就能看到效果了:
而且效果也是相当显著,最大的JS从1.4MB压缩到了330KB,整体的大小也从13MB压缩到了1.88MB,体积减少了,最开始的目的也达到了,按理说应该也结束了,但想着文件总大小减小了,加载应该也会变快吧,但事实是并没有因此变快,加载速度基本没有变化。
MinChunkSizePlugin—提升HTTP使用效率
冷静下来仔细想想,我们打包出来的JS有很多文件体积都非常小,那这样对网络传输或者说HTTP的使用效率就非常低,三次握手建立的HTTP连接,就传输一个1KB都不到的小文件,这样的文件多了,传输效率自然非常低下,所以接下来就是把那些非常小的JS合并成一个JS; 幸运的是,这个工作做起来也并不麻烦,webpack提供了官方的插件MinChunkSizePlugin
对chunk的大小进行限制,可以指定一个chunk最小必须超过多少字符,那么我们把这个插件加入到配置(vue.config.js)中:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpack = require('webpack');
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin(),
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 10000 // Minimum number of characters
})
]
}
}
复制代码
由于我并没有理解官方文档中说的characters具体是指什么(如果有知道的请一定要告诉我,非常感谢),然后尝试打包出来的结果和我设置预想的又有些出入,所以我最终只是对着webpack-bundle-analyzer
给出的打包结果对minChunkSize进行调参,最终设置的是1024 * 32 * 16
,优化的最终结果如下: