前端打包需要gzip压缩吗
# 前言
Vue 的 SPA 首屏加载特性,导致我们的系统第一次加载速度越来越缓慢,网速慢时可能达到十几秒的程度。
为了优化用户性能体验,我们开启 gzip 进行文件压缩,确实达到了显著的效果。
# 一、gzip 原理浅析
gzip 是一种压缩文件格式并且也是一个在类 Unix 上的一种文件解压缩的软件, 基于 HTTP 协议的网络传输中 gzip 经常被使用。
gzip 的基础是 DEFLATE,DEFLATE 是LZ77与哈夫曼编码的一个组合体
# LZ77
LZ77 的核心思路是 如果一个串中有两个重复的串,那么只需要知道第一个串的内容和后面串相对于第一个串起始位置的距离 + 串的长度。
比如: ABCDabcdABCDabcd123 → ABCDabcd(4,8)123。7 指的是往前第 4 个数开始,8 指的是重复串的长度
ABCDabcd(4,8)123 完全可以表示前面的串,它所占用字节更少, 并且没有二义性。
LZ77 用 滑动窗口(sliding-window compression)来实现这个算法。具体思路是扫描头从串的头部开始扫描串,在扫描头的前面有一个长度为 N 的滑动窗口。如果发现扫描头处的串和窗口里的 最长匹配串 是相同的,则用(两个串之间的距离,串的长度)来代替后一个重复的串,同时还需要添加一个表示是真实串还是替换后的“串”的字节在前面以方便解压(此串需要在 真实串和替换“串” 之前都有存在)
上图例子中的窗口大小为 6
实际过程中滑动窗口的大小是固定的,匹配的串也有最小长度限制,以方便 标识+两个串之间的距离+串的长度 所占用的字节是固定的 以及 不要越压缩体积越大
在前端的角度来看 gzip 这个压缩机制解释了为啥 CSS BEM 写法 gzip 压缩之后可以忽略长度,因为不管你的类多长它都会被压缩掉。
gzip 这个压缩机制还解释了 为什么 JPEG 图片 gzip 之后可能会变大, 因为 LZ77 对这种压缩过的矩阵类编码的文件无能为力
# gzip 与 zip
通常 gzip 仅用来压缩单个文件。多个文件的压缩归档通常是首先将这些文件合并成一个 tar 文件,然后再使用 gzip 进行压缩,最后生成的.tar.gz 或者.tgz 文件就是所谓的“tar 压缩包”。
注意不要将 gzip 和 ZIP 压缩格式混淆。ZIP 也使用 DEFLATE 算法,而且可移植性更好,不需要一个外部的归档工具就可以包容多个文件。
但是,由于 ZIP 对每个文件进行单独压缩而没有利用 文件间 的冗余信息(即固实压缩),所以 ZIP 的压缩率会稍逊于 tar 压缩包。
# 二、nginx 开启 gzip
Nginx 自带的 ngx_http_gzip_module 提供了开启 gzip 压缩的方式,有下面的一些常用配置:
# 开启
gzip on;
# 压缩等级,1-9。设置多少可以参考:http://serverfault.com/questions/253074/what-is-the-best-nginx-compression-gzip-level
gzip_comp_level 2;
# "MSIE [1-6]\." 比如禁止 IE6 使用 GZIP
gzip_disable regex ...
# 最小压缩文件长度
gzip_min_length 20;
# 使用 GZIP 压缩的最小 HTTP 版本
gzip_http_version 1.1;
# 压缩的文件类型,值是 [MIME type]
gzip_types text/html;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MIME type 各个类型的文档类别, 可以查看这里了解详情 MIME type MDN (opens new window)
# 三、本地 gzip 打包
nginx 自身处理请求然后压缩返回,会消耗对应的服务器内存。
nginx中可以直接使用gzip_static来缓存gzip文件,
本地压缩可以减少对服务端内存的使用,我们在客户端替 nginx 处理压缩文件这一步操作,nginx 便可直接使用我们压缩好的文件。
# 安装插件 compression-webpack-plugin
npm install compression-webpack-plugin -D
2
# vue.config.js 插件配置
const CompressionPlugin = require('compression-webpack-plugin')
module.export = {
configureWebpack: {
plugins: [
new CompressionPlugin({
filename: '[path].gz',
algorithm: 'gzip', //压缩算法
test: /\.js$|\.css$|\.html$/, //匹配文件
threshold: 10240, //压缩超过此大小的文件,以字节为单位,这里表示10kB以上的文件都走压缩
minRatio: 0.8,
deleteOriginalAssets: false //不删除原始文件 保留原始和压缩两种文件
})
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
根据上面学到的知识 test 一般只需要配置文本类文件,一定不要配置图片类文件
运行成功后,每个文件都生成了两种格式
# 配置 nginx
这里需要 nginx 对应的插件 http_gzip_static_module
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
gzip_static on; #启用静态压缩
}
}
2
3
4
5
6
7
8
9
10
11
# 开启 gzip 后
浏览器在请求资源的时候在 header 里面带上 accept-encoding: gzip 的参数。
Nginx 在接收到 Header 之后,发现如果有这个配置,则发送 GZIP 之后的文件(返回的 header 里也包含相关的说明),如果没有则发送源文件。
浏览器根据 response header 来处理要不要针对返回的文件进行解压缩然后展示。