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

Michael DiBlasio
Michael DiBlasio

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

应用屏幕截图

测量

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

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

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

Brotli 压缩

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

  • 比 JavaScript 的 gzip 小 14%
  • gzip 相比,HTML 缩减了 21%
  • CSS 大小比 gzip 缩减了 17%

如需使用 Brotli,您的服务器必须支持 HTTPS。所有新型浏览器都支持 Brotli。支持 Brotli 的浏览器将在 Accept-Encoding 标头中添加 br

Accept-Encoding: gzip, deflate, br

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

“网络”面板。“Content-encoding”列会显示用于各种资产的编码,包括 gzip 和 brotli (br)。

如何启用 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'));

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

使用动态 Brotli 压缩时的软件包大小。

现在,您可以在 Content-Encoding 标题中看到 brotli 是从 bz 应用的。 main.bundle.js225 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 控制台,查看由 Node 服务器提供的最终 public/ 目录中的内容。

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

现在,bundle 的 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 压缩的文件之前,请检查 Accept-Encoding 请求标头是否包含 br,以确认 Brotli 是否受支持:

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

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

软件包大小为 53.1 KB(从 225KB 缩减)

大功告成!您已使用 Brotli 压缩进一步压缩资源!

总结

此 Codelab 展示了 brotli 如何进一步缩减应用的总体大小。在受支持的情况下,brotligzip 更强大的压缩算法。