介绍:
本文深入探讨了前端性能优化中的关键一环------资源压缩,特指 Gzip 和 Brotli 这类用于减少网络传输体积的技术。你将了解到资源压缩如何工作,Gzip 与 Brotli 算法的差异与优势,以及为何"静态预压缩"策略是现代前端项目的更优选择。文中不仅详细解释了理论,更提供了具体的实践步骤:如何在Vite 项目中使用 vite-plugin-compression
插件生成 .gz
和 .br
预压缩文件,并给出了配置 Nginx 服务器以智能地、高效地提供这些压缩文件的示例,从而显著提升你的网站加载速度,改善用户体验。
资源压缩 (Asset Compression) 详解
首先,要明确一点,这里讨论的"资源压缩"通常指传输压缩 (Transfer Compression) ,它发生在服务器将资源发送给浏览器 的过程中,目的是减少网络传输的数据量。这与代码压缩/混淆 (Minification/Uglification) 不同,后者是在构建时通过移除空格、注释、缩短变量名等方式直接减小文件本身的大小。资源压缩是在这个基础上,使用通用的数据压缩算法(如 Gzip、Brotli)进一步压缩文件,以便更快地通过网络传输。
核心目标:
- 减少传输时间:文件体积越小,下载越快,尤其是在慢速网络下效果显著。
- 节省带宽:对用户和服务商都有利。
常用压缩算法:
-
Gzip:
- 目前最广泛支持和使用的压缩算法。几乎所有现代浏览器和服务器都支持。
- 基于 DEFLATE 算法,压缩率良好,压缩和解压速度快。
- 通常能将文本类资源(JS, CSS, HTML)压缩到原体积的 30%-50%。
-
Brotli (br):
- 由 Google 开发的较新算法。
- 通常比 Gzip 提供更高的压缩率(大约 15-25%),尤其对文本文件效果更佳。
- 压缩速度可能比 Gzip 稍慢(取决于压缩级别),但解压速度与 Gzip 相当或更快。
- 现代浏览器(Chrome, Firefox, Edge, Safari 11+)支持良好。服务器端也需要相应支持(如 Nginx 需要
ngx_brotli
模块)。
工作流程:
- 浏览器请求 :浏览器在发起 HTTP 请求时,通过
Accept-Encoding
请求头告诉服务器它支持哪些压缩算法。例如:Accept-Encoding: gzip, deflate, br
- 服务器处理 :
- 服务器检查请求的
Accept-Encoding
头。 - 如果服务器支持其中一种算法,并且配置了对该资源类型启用压缩,它就会发送压缩后的数据。
- 同时,服务器会在响应头中加入
Content-Encoding
字段,指明使用了哪种压缩算法。例如:Content-Encoding: br
- 服务器检查请求的
- 浏览器解压 :浏览器接收到响应后,看到
Content-Encoding
头,就会使用相应的算法解压数据,然后才解析和渲染内容。这个解压过程非常快,对用户几乎无感知。
实施策略:
有两种主要策略来提供压缩后的资源:
- 动态压缩 (On-the-fly Compression) :Web 服务器在每次收到请求时,实时地对资源进行压缩,然后再发送。
- 优点:配置相对简单。
- 缺点:消耗服务器 CPU 资源,尤其在高并发下可能影响性能。对于同一资源可能会重复压缩。
- 静态预压缩 (Pre-compression) :在项目构建时 就生成资源的压缩版本(例如,同时生成
main.js
,main.js.gz
,main.js.br
)。Web 服务器配置为:如果浏览器支持某种压缩格式,并且对应的预压缩文件存在,则直接发送该预压缩文件,无需实时压缩。- 优点:服务器端零 CPU 开销(只需提供静态文件),响应更快。可以在构建时使用更高的压缩级别获得更好的压缩率。
- 缺点:构建过程稍复杂,占用更多磁盘空间存储多个版本的文件。
对于现代前端项目,强烈推荐使用"静态预压缩"策略。
Vite 项目中实施静态预压缩
Vite 本身不内置预压缩功能,但可以通过插件轻松实现。一个常用的插件是 vite-plugin-compression
。
步骤:
-
安装插件: 打开你的终端,在项目根目录下运行:
bashpnpm add -D vite-plugin-compression
-
配置 Vite : 编辑你的
vite.config.js
文件:javascriptimport { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; // 1. 导入插件 import viteCompression from 'vite-plugin-compression'; // ... 其他导入 ... export default defineConfig({ plugins: [ vue(), // ... 其他插件 ... // 2. 添加插件配置 viteCompression({ verbose: true, // 是否在控制台输出压缩结果 disable: false, // 是否禁用压缩,默认 false threshold: 10240, // 文件大小大于 threshold (单位 byte) 才会被压缩。默认 0。 设置 10kb 可过滤掉小文件 algorithm: 'gzip', // 压缩算法,可选 ['gzip', 'brotliCompress', 'deflate', 'deflateRaw'] ext: '.gz', // 压缩后的文件扩展名 // deleteOriginFile: false // 是否删除原始文件,默认 false,建议保留原始文件以备后用或兼容不支持压缩的场景 }), // 3. 如果想同时生成 Brotli 压缩文件,可以再添加一个实例 viteCompression({ verbose: true, disable: false, threshold: 10240, algorithm: 'brotliCompress', ext: '.br', }), ], // ... 其他配置 ... });
配置说明:
verbose
: 在构建时显示压缩信息。threshold
: 文件大小阈值(字节)。只有大于这个大小的文件才会被压缩。设置一个合理的值(如 10kb)可以避免压缩过小的文件,因为压缩小文件可能收益不大甚至增加开销。algorithm
: 指定压缩算法。'gzip'
或'brotliCompress'
。ext
: 指定压缩后的文件扩展名。通常是.gz
或.br
。deleteOriginFile
: 强烈建议保持为false
。你需要原始文件作为不支持压缩的浏览器的后备,以及方便服务器配置查找文件。
-
运行构建: 执行你的生产构建命令:
bashpnpm build
-
检查结果 : 构建完成后,查看
dist/assets
目录(或你的输出目录)。你应该能看到除了原始的.js
,.css
文件外,还有对应的.js.gz
,.css.gz
,.js.br
,.css.br
文件。
配置 Web 服务器
仅仅生成了预压缩文件还不够,你必须配置你的 Web 服务器(如 Nginx, Apache 或你使用的托管平台),让它能够智能地提供这些文件。
Nginx 配置示例:
你需要确保 Nginx 安装了 ngx_http_gzip_static_module
和 ngx_http_brotli_module
(Brotli 可能需要手动编译安装或使用预编译版本)。
在你的 nginx.conf
或站点配置文件中的 server
或 location
块中添加:
nginx
server {
# ... 其他配置 ...
location ~* \.(js|css|html|json|svg|xml)$ { # 匹配需要压缩的文件类型
# 优先尝试提供 Brotli 预压缩文件
brotli_static on;
# 如果没有 Brotli 文件或浏览器不支持,尝试 Gzip 预压缩文件
gzip_static on;
# 设置正确的 MIME 类型(如果需要)
# types { ... }
# 缓存配置 (示例,根据实际情况调整)
expires 1y;
add_header Cache-Control "public, immutable";
# 指向你的构建产物目录
root /path/to/your/project/dist;
try_files $uri $uri/ /index.html; # SPA 回退路由
}
# ... 其他 location 配置 ...
}
解释:
brotli_static on;
: 告诉 Nginx 查找请求 URI 对应的.br
文件,如果存在且浏览器支持 Brotli (Accept-Encoding
包含br
),则直接发送.br
文件,并设置Content-Encoding: br
。gzip_static on;
: 如果 Brotli 条件不满足,则类似地查找并尝试提供.gz
文件。- 如果预压缩文件都不适用,Nginx 会回退到发送原始的未压缩文件。
其他服务器/平台:
- Apache : 使用
mod_deflate
(配合AddEncoding
指令查找预压缩文件) 和mod_brotli
。 - Node.js (Express) : 可以使用
express-static-gzip
中间件,它能自动处理预压缩文件的提供。 - 静态托管平台 (Vercel, Netlify等) : 这些平台通常自动处理 Gzip 和 Brotli 压缩(包括提供预压缩文件或动态压缩),你一般无需额外配置服务器,只需确保构建时生成了文件即可。请查阅你所使用平台的文档确认。
通过实施静态预压缩并在服务器端正确配置,你可以显著提升应用的加载性能,尤其对于内容较多的 JS 和 CSS 文件效果非常明显。
注意:资源压缩(Gzip/Brotli)不会压缩数图片格式(如 JPG, PNG, GIF, WebP, AVIF)。
原因如下:
-
图片本身已经是压缩格式:
- 像 JPEG、PNG、GIF、WebP、AVIF 这些常见的图片格式,它们本身就已经使用了专门针对图像数据的内置压缩算法(有损或无损)。这些算法非常高效地利用了图像的视觉冗余来减小文件大小。
- 例如,JPEG 使用了离散余弦变换等技术,非常适合照片类图像的有损压缩。PNG 使用了 DEFLATE(与 Gzip 相同的基础算法之一),但它是为无损压缩图像像素数据而优化的。WebP 和 AVIF 提供了更现代、更高效的压缩方法。
-
Gzip/Brotli 对已压缩数据效果不佳:
- Gzip 和 Brotli 这类通用压缩算法主要是通过查找和替换重复的文本模式来工作的。它们对于文本类文件(HTML, CSS, JS, JSON, SVG 等)效果显著,因为这些文件中有大量的重复字符串和模式。
- 而已经高度压缩过的图片文件(尤其是像 JPEG 这样的有损格式),其数据流通常看起来更像是随机噪声,几乎没有 Gzip/Brotli 能够有效利用的重复文本模式。
- 尝试对这些已经压缩过的图片再应用 Gzip 或 Brotli,通常几乎不会再减小体积 ,甚至在极少数情况下,由于压缩算法本身的开销,文件体积反而可能略微增大。这白白浪费了服务器的 CPU 资源(如果是动态压缩)或构建时间(如果是静态预压缩)。
-
关注点分离:图片优化 vs. 传输压缩:
- 图片的优化 应该在资源本身 层面进行:
- 选择合适的格式:根据图片内容选择 JPEG, PNG, WebP, AVIF 等。
- 适当的压缩级别:使用图像编辑工具或在线工具(如 TinyPNG, Squoosh.app)在可接受的视觉质量范围内进行压缩。
- 调整尺寸:提供适合显示区域大小的图片,避免传输不必要的大图。
- 响应式图片 :使用
<picture>
标签或srcset
属性为不同屏幕提供不同尺寸或格式的图片。
- 传输压缩 (Gzip/Brotli) 则专注于优化文本类资源的传输过程。
- 图片的优化 应该在资源本身 层面进行: