此 Codelab 是缩小和压缩网络载荷 Codelab 的扩展,并假定您熟悉压缩的基本概念。与其他压缩算法(如 gzip)相比,此 Codelab 探讨了 Brotli 压缩 (br) 如何进一步降低压缩比并减小应用的总体大小。

测量
在深入研究如何添加优化之前,最好先分析应用的当前状态。
- 点击 Remix to Edit 使项目可供修改。
- 如需预览网站,请按查看应用。然后按全屏图标
。
在之前的压缩和缩小网络载荷 Codelab 中,我们将 main.js 的大小从 225 KB 减小到了 61.6 KB。在此 Codelab 中,您将探索 Brotli 压缩如何进一步减小此 bundle 大小。
Brotli 压缩
Brotli 是一种较新的压缩算法,与 gzip 相比,它能提供更好的文本压缩效果。根据 CertSimple 的数据,Brotli 的性能如下:
- 比
gzipfor JavaScript 小 14% - 比 HTML 的
gzip小 21% - 比 CSS 的
gzip小 17%
如需使用 Brotli,您的服务器必须支持 HTTPS。所有现代浏览器都支持 Brotli。支持 Brotli 的浏览器将在 Accept-Encoding 标头中包含 br:
Accept-Encoding: gzip, deflate, br
您可以使用 Chrome 开发者工具“网络”标签页中的 Content-Encoding 字段(Command+Option+I 或 Ctrl+Alt+I)确定所用的压缩算法:
如何启用 Brotli
您设置网络服务器以发送 Brotli 编码资源的方式取决于您计划如何对这些资源进行编码。您可以选择在请求时使用 Brotli 动态压缩资源(动态),也可以提前对资源进行编码,以便在用户请求时资源已处于压缩状态(静态)。
动态压缩
动态压缩是指在浏览器请求资源时,实时压缩资源。
优点
- 无需创建和更新已保存的压缩版素材资源。
- 即时压缩功能尤其适合动态生成的网页。
缺点
- 以更高级别压缩文件以实现更高的压缩率需要更长时间。这可能会导致性能下降,因为用户需要等待资源压缩完毕后才能由服务器发送。
使用 Node 和 Express 进行动态压缩
server.js 文件负责设置托管应用的 Node 服务器。
const express = require('express');
const app = express();
app.use(express.static('public'));
const listener = app.listen(process.env.PORT, function() {
console.log(`Your app is listening on port ${listener.address().port}`);
});
此代码只是导入 express 并使用 express.static 中间件来加载 public/directory 中的所有静态 HTML、JS 和 CSS 文件(这些文件由 webpack 在每次构建时创建)。
为了确保每次请求所有资源时都使用 Brotli 进行压缩,可以使用 shrink-ray 模块。首先,在 package.json 中将其添加为 devDependency:
"devDependencies": {
// ...
"shrink-ray": "^0.1.3"
},
并将其导入到服务器文件 server.js 中:
const express = require('express');
const shrinkRay = require('shrink-ray');
并在挂载 express.static 之前将其添加为中间件:
// ...
const app = express();
// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));
现在,重新加载应用,然后在“网络”面板中查看软件包大小:
您现在可以在 Content-Encoding 标头中看到 brotli 已从 bz 应用。
main.bundle.js 从 225 KB 减少到 53.1 KB!与 gzip (61.6 KB) 相比,此模型小了约 14%。
静态压缩
静态压缩的理念是提前压缩并保存资源。
优点
- 由于压缩级别较高而导致的延迟不再是问题。无需即时压缩文件,因为现在可以直接提取文件。
缺点
- 每次构建都需要压缩资源。如果使用较高的压缩级别,构建时间可能会显著增加。
使用 webpack 通过 Node 和 Express 进行静态压缩
由于静态压缩涉及提前压缩文件,因此可以修改 webpack 设置,以便在构建步骤中压缩资源。为此,可以使用 brotli-webpack-plugin。
首先,在 package.json 中将其添加为 devDependency:
"devDependencies": {
// ...
"brotli-webpack-plugin": "^1.1.0"
},
与其他任何 webpack 插件一样,在配置文件 webpack.config.js 中导入该插件:
var path = require("path");
//...
var BrotliPlugin = require('brotli-webpack-plugin');
并将其包含在 plugins 数组中:
module.exports = {
// ...
plugins: [
// ...
new BrotliPlugin({
asset: '[file].br',
test: /\.(js)$/
})
]
},
插件数组使用以下实参:
asset:目标资产名称。[file]替换为原始素材资源文件名。test:与此正则表达式匹配的所有资源(即以.js结尾的 JavaScript 资源)都会被处理。
例如,main.js 将重命名为 main.js.br。
当应用重新加载并重新构建时,系统现在会创建主软件包的压缩版本。打开 Glitch 控制台,查看由 Node 服务器提供的最终 public/ 目录中的内容。
- 点击工具按钮。
- 点击控制台按钮。
- 在控制台中,运行以下命令以切换到
public目录并查看其所有文件:
cd public
ls -lh
现在,系统也会将软件包的 brotli 压缩版本 main.bundle.js.br 保存到此处,并且其大小比 main.bundle.js 小 ~76%(225 KB 与 53 KB)。
接下来,指示服务器在请求这些文件的原始 JS 版本时,发送经过 brotli 压缩的文件。为此,您可以在使用 express.static 提供文件之前,在 server.js 中定义新路由。
const express = require('express');
const app = express();
app.get('*.js', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
next();
});
app.use(express.static('public'));
app.get 用于告知服务器如何响应针对特定端点的 GET 请求。然后,使用回调函数来定义如何处理此请求。路线的运作方式如下:
- 将
'*.js'指定为第一个实参意味着,此函数适用于每个用于提取 JS 文件的端点。 - 在回调中,
.br会附加到请求的网址,并且Content-Encoding响应标头会设置为br。 Content-Type标头设置为application/javascript; charset=UTF-8以指定 MIME 类型。- 最后,
next()确保序列继续执行下一个可能的回调。
由于某些浏览器可能不支持 brotli 压缩,因此请先确认是否支持 brotli,然后再返回 brotli 压缩的文件,方法是检查 Accept-Encoding 请求标头是否包含 br:
const express = require('express');
const app = express();
app.get('*.js', (req, res, next) => {
if (req.header('Accept-Encoding').includes('br')) {
req.url = req.url + '.br';
console.log(req.header('Accept-Encoding'));
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
}
next();
});
app.use(express.static('public'));
应用重新加载后,再次查看“网络”面板。
大功告成!您已使用 Brotli 压缩来进一步压缩资源!
总结
此 Codelab 演示了 brotli 如何进一步减小应用的总体大小。在支持的情况下,brotli 是一种比 gzip 更强大的压缩算法。