使用 gzip 压缩网络载荷

此 Codelab 探讨了如何缩减和压缩 JavaScript bundle 来降低页面性能, 应用的请求大小

应用屏幕截图

测量

在深入研究如何进行优化之前,最好先分析 应用的当前状态。

  • 如需预览网站,请按查看应用。然后按 全屏 全屏

此应用也在“移除未使用的” “代码”Codelab,可让您为自己最喜欢的代码投票 小猫。🐈

现在,我们来看看此应用的大小:

  1. 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
  2. 点击网络标签页。
  3. 选中停用缓存复选框。
  4. 重新加载应用。

“网络”面板中的原始内容集大小

尽管在“移除未使用的代码”部分已经取得了很多进展, 缩减此 bundle 的大小,225 KB 仍相当大。

缩减大小

请参考以下代码块。

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

如果将此函数保存在它自己的文件中,则文件大小大约为 112 B(字节)

如果移除所有空格,生成的代码将如下所示:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

现在,文件大小约为 83 B。如果减少 更改名称的长度以及修改某些表达式,那么最终代码 最终将如下所示:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

文件大小现已达到 62 B

每一步,代码的阅读难度都会增加。不过,浏览器的 JavaScript 引擎会以完全相同的方式解读上述每项信息。通过 以这种方式混淆代码的优势有助于缩小文件 尺寸。112B 开始时其实并不多,但仍然有 50% !

在此应用中,webpack版本 4 用作 模块打包器。具体版本可在 package.json 中查看。

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

默认情况下,版本 4 在生产模式下已缩减 bundle 的大小。它使用 TerserWebpackPluginTerser 的插件。 Terser 是一种用于压缩 JavaScript 代码的常用工具。

要了解缩减后的代码是什么样的,请继续并点击 main.bundle.js(同时仍位于开发者工具的 Network 面板中)。现在,点击 响应标签页。

缩减响应大小

经过缩减和破坏的最终形式代码会显示在响应正文中。 如需了解软件包在不缩减大小的情况下的大小,请打开 webpack.config.js 并更新 mode 配置。

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

重新加载应用,并通过 开发者工具 Network 面板

媒体包大小为 767 KB

差异很大!😅

请务必先还原此处的更改,然后再继续。

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

在应用中加入缩减代码大小的流程取决于所使用的工具 所用资源:

  • 如果使用的是 webpack v4 或更高版本,则无需执行任何其他操作 因为在生产模式下,代码默认会被缩减。👍
  • 如果使用的是旧版 Webpack,请安装并包含 TerserWebpackPlugin 添加到 Webpack 构建流程中文档 将对此进行详细介绍
  • 还有其他缩减大小插件,可以改用。 例如 BabelMinifyWebpackPluginClosureCompilerPlugin
  • 如果根本没有使用模块打包器,请使用 Terser 作为 CLI 工具,或直接将其添加为依赖项。

压缩

虽然术语“压缩”有时用于解释代码的 它实际上并不会在压缩过程中压缩 字面意义。

压缩通常是指使用数据修改的代码 压缩算法。与收缩功能不同 有效代码,则需要先将压缩后的代码解压缩,然后才能使用。

对于每个 HTTP 请求和响应,浏览器和网络服务器都可以将 要包含的标题 有关正在提取或接收的资源的其他信息。可以是 可在开发者工具 Network 面板内的 Headers 标签页中查看,其中有三种类型 示例:

  • General 表示与整个请求-响应相关的常规标头 互动
  • Response Headers 显示实际响应的专属标头列表 。
  • Request Headers 会显示 客户端。

查看 Request Headers 中的 accept-encoding 标头。

接受编码标头

accept-encoding:浏览器使用 accept-encoding 来指定 编码格式或压缩算法。有很多 文本压缩算法,但只有三种 用于压缩(和解压缩)HTTP 网络请求:

  • Gzip (gzip):最常用的压缩工具 服务器和客户端交互的格式。它建立在 Deflate 的基础上, 算法,目前所有的浏览器均支持此功能。
  • Deflate (deflate):不常用。
  • Brotli (br):较新的压缩方法 旨在进一步提高压缩比的算法, 提高网页加载速度在 大多数浏览器的最新版本

本教程中的示例应用与 移除未使用的代码 Codelab,但以下情况除外: Express 现在用作服务器框架。在未来 我们只探讨了静态压缩和动态压缩两个部分。

动态压缩

动态压缩涉及在素材资源生成时即时对其进行压缩 。

优点

  • 创建和更新已保存的压缩版素材资源无需 完成。
  • 实时压缩功能特别适用于 动态生成的图片。

缺点

  • 在较高级别压缩文件以实现更好的压缩比 用时更长在用户等待素材资源更新时,这可能会导致性能下降 在服务器发送之前对其进行压缩。

使用 Node/Express 进行动态压缩

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

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 加载网页中的所有静态 HTML、JS 和 CSS 文件, public/ 目录(这些文件由 webpack 在每次构建时创建)。

为了确保所有资源在每次收到请求时都会进行压缩, 压缩中间件库可以 。首先,在 package.json 中将其添加为 devDependency

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

将其导入服务器文件 server.js

const express = require('express');
const compression = require('compression');

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

//...

const app = express();

app.use(compression());

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

//...

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

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

从 225 KB 到 61.6 KB!现在,在 Response Headers 中,content-encoding 标头显示服务器正在发送这个使用 gzip 编码的文件。

内容编码标头

静态压缩

静态压缩背后的理念是压缩和保存资源 。

优点

  • 高压缩级别导致的延迟不再是问题。 无需实时进行压缩,因为现在可直接提取文件。

缺点

  • 每次构建时都需要压缩资源。构建时间可能会增加 如果使用高压缩级别,则会出现明显的差异。

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

由于静态压缩涉及预先压缩文件,因此 webpack 可以在构建步骤中修改设置,以压缩资源。 CompressionPlugin 可以用于实现这一点

首先,在 package.json 中将其添加为 devDependency

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

与任何其他 webpack 插件一样,请将其导入配置文件, webpack.config.js:

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

并将其包含在 plugins 数组中:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

默认情况下,该插件会使用 gzip 压缩 build 文件。一睹为快 参阅文档 以了解如何添加选项,以便使用其他算法或包含/排除选项 特定文件

当应用重新加载并重新构建时,系统会生成主软件包的压缩版本 已创建完成。打开 Glitch 控制台,查看 最终的 public/ 目录。

  • 点击工具按钮。
  • 点击控制台按钮。
  • 在控制台中,运行以下命令以切换到 public 目录并查看其中的所有文件:
cd public
ls

最终输出的文件位于公共目录中

压缩包的 Gzip 版本 main.bundle.js.gz 现在在此处另存为 。默认情况下,CompressionPlugin 还会压缩 index.html

接下来需要做的是告诉服务器 文件的原始 JS 版本。为此, 方法是在 server.js 中定义一个新路由,然后再使用 express.static

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

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

//...

app.get 用于告知服务器如何响应 特定端点。然后,使用回调函数来定义如何处理 请求。路线的运作方式如下:

  • 指定 '*.js' 作为第一个参数意味着这适用于每个 用于提取 JS 文件而触发的端点。
  • 在回调中,.gz 会附加到请求的网址,并且 Content-Encoding 响应标头设置为 gzip
  • 最后,next() 可确保序列继续执行任何回调 可能是下一个。

应用重新加载后,请再次查看 Network 面板。

使用静态压缩缩减软件包大小

和以前一样,软件包大小显著减小!

总结

此 Codelab 介绍了缩减和压缩源代码的过程。 这两种技术已成为许多工具中的默认技术, 因此重要的是,确定您的工具链是否已 还是您应该自行开始同时采用这两个流程。