本文讨论在私有化需求场景下, Node.js 服务如何压缩静态资源,并开启强缓存。CDN 场景需和 CDN 厂商沟通,不在本文范围内。
同时支持 gzip/br 压缩
因为 br 存在兼容性问题,具体可参考:Can I Use Brotli。如果项目的目标浏览器都支持 Brotli,则可以不支持 gzip 压缩。
静态压缩(推荐)
静态压缩是在构建时生成 gzip 和 br 文件。
优点是:
- 服务端运行时可快速响应压缩文件。
- 相比于动态压缩,可以配置更高的压缩级别。
缺点是:会增加构建时间和资源上传时间。
配置 webpack 构建时生成 gzip/br 文件
在 webpack 中增加两个插件,一个用于生成 gzip,一个用于生成 brotli。具体参数可参考 CompressionWebpackPlugin。
new CompressionPlugin({
filename: '[path][base].gz',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
})
new CompressionPlugin({
filename: '[path][base].br',
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
compressionOptions: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
},
},
threshold: 10240,
minRatio: 0.8,
})
服务端 express-static-gzip 根据 Accept-Encoding 自动降级
由于 express-static-gzip 是基于 express.static() 开发的,所以支持 express.static() 的所有功能。但其增加的额外功能有两点:
- 可以根据 Accept-Encoding 请求头解析不同的压缩文件并响应。
- 解析压缩文件时有优先级顺序,brotli > gzip > raw,支持自动降级解析。
代码也很简单,如下所示。
expressStaticGzip(StaticDir, {
enableBrotli: true,
orderPreference: ['br'],
serveStatic: {
maxAge: '30 days', // 开启强缓存 30 天
}
});
动态压缩(不推荐)
动态压缩是指服务在响应静态资源的时候,服务端对静态资源进行实时压缩返回。优缺点和静态压缩相反。
使用的三方包为 shrink-ray。使用也很简单,只需要一行代码,其内部已经对 Accept-Encoding 和 MIME 类型进行检查。
app.use(shrinkRay());
使用 brotli 压缩的前提条件
在 Chrome 中只有 https 的网站发起的请求头 Accept-Encoding 中才会加上 br 选项,此时服务端才会响应 brotli 压缩的资源。因此只有网站支持 https 时,开启 br 压缩才有价值。