使用 brotli 缩减和压缩网络载荷

米歇尔·迪布拉西奥
Michael DiBlasio

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

应用屏幕截图

测量

在深入了解添加优化措施之前,最好先分析应用的当前状态。

  1. 点击 Remix to Edit 使项目可修改。
  2. 如需预览网站,请按查看应用,然后按全屏 全屏

在之前的“缩减和压缩网络载荷”Codelab 中,我们将 main.js 的大小从 225 KB 缩减到了 61.6 KB。在此 Codelab 中,您将探索 Brotli 压缩如何进一步缩减此 bundle 大小。

Brotli 压缩

Brotli 是一种较新的压缩算法,可以提供比 gzip 更好的文本压缩结果。根据 CertSimple,Brotli 的性能为:

  • 比用于 JavaScript 的 gzip 小 14%
  • gzip 小 21%(对于 HTML)
  • gzip 小 17%(适用于 CSS)

要使用 Brotli,您的服务器必须支持 HTTPS。大多数浏览器的最新版本都支持 Brotli。支持 Brotli 的浏览器会在 Accept-Encoding 头文件中包含 br

Accept-Encoding: gzip, deflate, br

您可以通过 Chrome 开发者工具“网络”标签页(Command+Option+ICtrl+Alt+I)中的 Content-Encoding 字段确定使用哪种压缩算法:

“网络”面板

启用 Brotli

动态压缩

动态压缩涉及到在浏览器请求时即时压缩资源。

优点

  • 不需要创建和更新资源的已保存压缩版本。
  • 即时压缩功能尤其适用于动态生成的网页。

缺点

  • 为了获得更好的压缩比,压缩较高级别的文件需要花费更长时间。当用户等待资源在服务器发送之前进行压缩时,这可能会导致性能下降。

使用 Node/Express 动态压缩

server.js 文件负责设置托管应用的节点服务器。

var express = require('express');

var app = express();

app.use(express.static('public'));

var 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 中:

var express = require('express');
var shrinkRay = require('shrink-ray');

在装载 express.static 之前,请将其作为中间件添加:

//...
var app = express();

// compress all requests
app.use(shrinkRay());

app.use(express.static('public'));

现在,重新加载应用,并在“Network”面板中查看 bundle 大小:

采用动态 Brotli 压缩的软件包大小

您现在可以在 Content-Encoding 标头中看到从 bz 应用 brotli 的情况。main.bundle.js 已从 225 KB 缩减到 53.1 KB!与 gzip (61.6 KB) 相比,该大小约降低了 14%。

静态压缩

静态压缩背后的理念是提前压缩并保存资源。

优点

  • 因此,您不必再担心因压缩级别过高而导致的延迟。无需任何动态文件即可压缩文件,因为文件现在可以直接提取。

缺点

  • 每次构建时都需要压缩资源。如果使用高压缩级别,构建时间可能会显著增加。

使用 Node/Express 和 webpack 进行静态压缩

由于静态压缩涉及提前压缩文件,因此可以在构建步骤中修改 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 控制台,查看节点服务器提供的最终 public/ 目录中的内容。

  1. 点击工具按钮。
  2. 点击控制台按钮。
  3. 在控制台中,运行以下命令切换到 public 目录并查看其所有文件:
cd public
ls -lh
采用静态 Brotli 压缩的软件包大小

软件包的 brotli 压缩版本 main.bundle.js.br 现在也保存在此处,其大小比 main.bundle.js 小约 76%(225 KB 比 53 KB)。

接下来,指示服务器在每次请求这些 brotli 压缩文件的原始 JS 版本时发送它们。这可以通过在 server.js 中定义一个新路由来实现,然后再使用 express.static 传送文件。

var express = require('express');

var 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

var express = require('express');

var 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'));

应用重新加载后,请再次查看“网络”面板。

软件包大小为 53.1 KB(从 225 KB 开始)

成功!您已使用 Brotli 压缩功能进一步压缩了资源!

总结

此 Codelab 说明了 brotli 如何进一步缩减应用的总大小。在支持的情况下,brotli 是比 gzip 更强大的压缩算法。