Vite 预压缩 + Nginx gzip_static:为什么生产环境更推荐静态压缩?
上一篇文章,我们介绍了 Nginx 开启 Gzip 压缩。
开启之后,一个 900KB 的 JavaScript 文件,经过压缩后可能只有 300KB 左右,页面加载速度也会明显提升。
很多同学看到这里都会认为:
开启 Gzip 不就已经优化完成了吗?
其实还没有。
虽然 Gzip 能减少网络传输的数据量,但它还有一个容易被忽略的问题:
服务器需要实时压缩。
今天我们就来聊聊,为什么很多生产环境都会采用:
Vite 预压缩 + Nginx gzip_static
这种方案。
一、实时 Gzip 到底做了什么?
上一篇我们知道:
浏览器请求:
app.js
Nginx 收到请求以后:
读取 app.js
↓
Gzip 压缩
↓
返回浏览器
整个流程如下:
浏览器
│
GET app.js
│
▼
Nginx
│
读取 JS
│
Gzip 压缩
│
▼
返回压缩后的内容
看起来没有什么问题。
但是:
这里的 Gzip 压缩,每一次请求都会执行。
二、为什么实时压缩会消耗 CPU?
假设现在只有一个用户。
流程就是:
读取
↓
压缩
↓
返回
如果:
100 个用户同时访问:
用户1
↓
压缩
↓
返回
用户2
↓
压缩
↓
返回
用户3
↓
压缩
↓
返回
......
服务器需要不停重复执行:
读取
↓
压缩
↓
发送
也就是说:
虽然 JavaScript 永远都是同一个 JavaScript。
但是:
服务器却可能压缩了一百遍。
三、为什么不能提前压好?
很多同学会想到:
既然:
app.js
每天都是一样的。
为什么不在打包的时候:
提前压缩
等用户访问的时候:
直接发送?
答案就是:
完全可以。
这也是:
预压缩(Pre Compression)
的核心思想。
四、什么是预压缩?
所谓预压缩,其实就是:
在项目打包阶段,把需要压缩的文件提前压好。
例如:
以前:
dist
├── app.js
├── style.css
├── logo.png
现在:
打包以后:
dist
├── app.js
├── app.js.gz
├── style.css
├── style.css.gz
├── logo.png
也就是说:
除了正常文件。
还会额外生成:
.gz
文件。
五、浏览器到底下载哪个文件?
很多人第一次看到:
app.js.gz
都会疑惑:
浏览器是不是直接下载:
.gz
答案是:
不是。
浏览器请求的依然是:
GET /app.js
Nginx 收到以后:
发现:
app.js.gz
已经存在。
于是:
直接返回:
app.js.gz
浏览器收到以后:
自动解压。
整个过程如下:
浏览器
↓
GET app.js
↓
Nginx
↓
发现 app.js.gz
↓
直接返回
↓
浏览器自动解压
用户完全不知道:
服务器其实返回的是:
.gz
文件。
六、Vite 如何生成 .gz 文件?
Vite 本身不会自动生成压缩文件。
通常需要借助:
vite-plugin-compression
安装:
npm install vite-plugin-compression -D
然后:
修改:
vite.config.js
配置插件:
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({
filter: /\.(js|css)$/i,
threshold: 1024,
algorithm: 'gzip',
ext: '.gz'
})
]
})
配置完成以后:
重新执行:
npm run build
打开:
dist
目录。
就会看到:
app.js
app.js.gz
style.css
style.css.gz
说明:
预压缩已经成功。
七、Nginx 为什么还要配置 gzip_static?
虽然:
.gz
已经存在。
但是:
Nginx 默认并不会主动读取。
因此:
需要开启:
gzip_static on;
这句话的意思就是:
如果发现存在对应的 .gz 文件,就直接返回它。
例如:
浏览器请求:
app.js
Nginx:
先检查:
有没有:
app.js.gz
如果有:
直接返回:
app.js.gz
如果没有:
再按照普通 Gzip 的方式处理。
所以:
gzip_static on;
就是连接:
预压缩
和
浏览器
之间的重要桥梁。
八、实时压缩 VS 预压缩
很多同学容易混淆。
其实它们最大的区别就在于:
压缩发生的时间不同。
普通 Gzip:
浏览器请求
↓
Nginx
↓
现场压缩
↓
返回
预压缩:
项目打包
↓
提前压缩
↓
上传服务器
浏览器访问:
Nginx
↓
直接返回
↓
结束
所以:
实时 Gzip:
服务器需要:
CPU
不停压缩
预压缩:
服务器:
直接读取
直接返回
CPU 消耗明显更低。
九、是不是所有项目都需要预压缩?
其实并不是。
如果:
项目非常小。
例如:
几十 KB
或者:
访问量很低。
那么:
普通 Gzip:
已经足够。
但是:
如果:
Vue
React
后台管理
博客
官网
企业门户
这些项目:
通常:
JS
CSS
几百 KB
甚至几 MB
而且:
访问量越来越高。
那么:
预压缩:
就会带来不错的收益。
十、预压缩还有哪些好处?
除了:
减少服务器 CPU。
还有另外一个优势。
例如:
打包以后:
app.js
一直不会变化
对应:
app.js.gz
也一直不会变化。
所以:
部署以后:
服务器基本只负责:
读取
↓
发送
整个流程更加简单。
对于静态资源来说:
这是目前比较推荐的一种部署方式。
十一、那开启 gzip 还有意义吗?
很多人会问:
既然:
gzip_static
这么好。
是不是:
gzip on;
就可以删除了?
其实:
一般不会。
通常:
生产环境:
两者都会保留:
gzip on;
gzip_static on;
原因很简单。
项目里面:
并不是所有资源:
都会提前生成:
.gz
如果:
没有:
app.js.gz
Nginx:
仍然可以:
实时 Gzip
这样:
兼容性更好。
所以:
很多生产环境都会:
gzip
+
gzip_static
一起使用。
十二、总结
Gzip 能够减少网络传输的数据量。
但是:
普通 Gzip:
需要服务器在每次请求时进行实时压缩。
而:
预压缩:
则是在项目打包阶段,提前生成:
.gz
文件。
配合:
gzip_static on;
Nginx 可以直接返回已经压缩好的资源,不再重复执行压缩计算,从而进一步降低服务器 CPU 开销。
对于 Vue3、React 等前端项目来说,推荐采用:
Vite 打包
↓
生成 .gz 文件
↓
Nginx 开启 gzip_static
↓
浏览器自动解压
这种方式部署静态资源。
在下一篇文章中,我们将介绍一个非常实用的工具:
rollup-plugin-visualizer。
它能够生成一份可视化打包分析报告,帮助我们快速找到:
到底是谁,把你的 JavaScript 包撑到了几 MB。