渐进式 Web 应用:使用 Workbox

1. 欢迎

在本实验中,您将使用现有的 Service Worker 获取网站,并将其转换为使用 Workbox。这是渐进式 Web 应用工作坊的一系列配套 Codelab 中的第二个。上一个 Codelab 是离线。本系列还有 6 个 Codelab。

学习内容

  • 转换现有 Service Worker 以使用 Workbox
  • 为 PWA 添加离线回退

注意事项

  • HTML 和 JavaScript 基础知识

所需条件

2. 进行设置

首先,克隆或下载完成此 Codelab 所需的起始代码:

如果您克隆了代码库,请确保您位于 pwa03--workbox 分支中。该 ZIP 文件还包含相应分支的代码。

此代码库需要 Node.js 14 或更高版本。获得代码后,在代码的文件夹中通过命令行运行 npm ci,以安装所需的所有依赖项。然后,运行 npm start 以启动 Codelab 的开发服务器。

源代码的 README.md 文件提供了对所有分发文件的说明。此外,以下是您将在整个 Codelab 中使用的关键现有文件:

密钥文件

  • service-worker.js - 应用的服务工作线程文件
  • offline.html - 在网页不可用时使用的离线 HTML

3. 迁移到 Workbox

查看现有的 service worker,预缓存似乎可以分为两步:

  • 在 Service Worker 安装期间缓存相关文件
  • 再次使用“仅缓存”策略提供这些文件

index.html 文件和 / 路由仍然适合预缓存,因为此 Web 应用的 HTML 不会发生太大变化,但其他文件(如 CSS 和 JavaScript)可能会发生变化,我们并不希望每次发生变化时都需要经历整个 Service Worker 生命周期。此外,当前的 Service Worker 仅考虑了部分 CSS 和 JavaScript,我们希望涵盖所有这些文件。使用“过时后重新验证”策略缓存这些项更有意义;快速响应,可根据需要在后台更新。

重新审视预缓存

迁移到 Workbox 后,我们无需保留任何现有代码,因此请删除 service-worker.js 中的所有内容。在上一个实验中,我们已将此 Service Worker 设置为可编译,因此我们可以在此处使用 ESModule 导入从其 NPM 模块中引入 Workbox。我们先来回顾一下预缓存。在 service-worker.js 中,添加以下代码:

import { warmStrategyCache } from 'workbox-recipes';
import { CacheFirst } from 'workbox-strategies';
import { registerRoute } from 'workbox-routing';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';

// Set up page cache
const pageCache = new CacheFirst({
  cacheName: 'page-cache',
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200],
    }),
    new ExpirationPlugin({
      maxAgeSeconds: 30 * 24 * 60 * 60,
    }),
  ],
});

warmStrategyCache({
  urls: ['/index.html', '/'],
  strategy: pageCache,
});

registerRoute(({ request }) => request.mode === 'navigate', pageCache);

说明

如需为 /index.html/ 设置预缓存,需要从五个模块中拉取。虽然这看起来可能很多,但此代码比之前编写的代码强大得多。

首先,我们设置一个新的“先缓存”缓存策略,而不是“仅缓存”策略,以便根据需要将其他网页添加到缓存中。为其指定名称,即 page-cache。Workbox 策略可以采用多种插件,这些插件会影响从缓存中保存和检索内容的生命周期。在此示例中,我们使用了两个插件:Cacheable Response 插件和 Expiration 插件,以确保仅缓存良好的服务器响应,并确保缓存中的每个项目在 30 天后都会被清空。

接下来,使用“预热策略缓存”Workbox 配方,通过 /index.html/ 预热策略的缓存。这会在 service worker 的安装事件期间将这些项添加到此缓存中。

最后,注册新路线。任何网页导航请求都将由“先缓存”策略管理,该策略会从缓存或网络中提取内容,然后缓存响应。

缓存资源

在解决了路线预缓存问题后,现在可以重新实现网站资源(即 CSS 和 JavaScript)的缓存。为此,请先将 StaleWhileRevalidate 添加到 workbox-strategies 导入项中,然后将以下代码添加到 Service Worker 的底部:

// Set up asset cache
registerRoute(
  ({ request }) => ['style', 'script', 'worker'].includes(request.destination),
  new StaleWhileRevalidate({
    cacheName: 'asset-cache',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
    ],
  }),
);

说明

此路由首先会确定请求的类型是样式、脚本还是工作器,分别对应于 CSS、JavaScript 或 Web Worker。如果可以,它会使用“过时但需重新验证”策略,尝试先从缓存中提供服务,如果缓存中没有,则回退到网络,同时尝试从网络更新缓存中的版本(如果可能)。与页面策略类似,此策略只会缓存良好的响应。

4. 添加离线回退

将原始的 Service Worker 迁移到 Workbox 后,还需要做一件事,才能防止 PWA 在离线时崩溃:添加离线回退。

您可以为离线时可能无法使用的任何内容设置离线回退,例如网页、字体、CSS、JavaScript、图片等。至少应为所有 PWA 设置页面回退,这样一来,如果用户前往缓存中没有的页面,他们仍会停留在应用的情境中。

Workbox 配方提供了一个离线回退配方,可用于实现此目的!如需使用它,请先将 offlineFallback 添加到 workbox-recipes 导入项中,然后将以下代码添加到 Service Worker 的底部:

// Set up offline fallback
offlineFallback({
  pageFallback: '/offline.html',
});

说明

离线后备配方会设置一个仅缓存策略,该策略会使用提供的后备资源进行预热。然后,它会设置一个 Workbox 默认捕获处理程序,捕获任何失败的路由请求(如果缓存中没有任何内容,并且无法访问网络上的某些内容),从缓存中提取相关文件的内容,并在请求继续失败时将其作为内容返回。

5. 恭喜!

您已了解如何使用 Workbox 为路由设置缓存策略,并为 PWA 提供离线回退。

本系列中的下一个 Codelab 是 IndexedDB