Workbox

随着 PWA 的增长,维护 Service Worker 和缓存存储逻辑可能是一个挑战。Workbox 是一组开源库,可帮助解决此问题。Workbox 封装了低级别 API(如 Service Worker API 和 Cache Storage API),并公开了更便于开发者使用的界面。

它可以帮助完成的一些任务包括:将缓存策略与路径(或路由模式)匹配、使用流以及使用后台同步等功能以及适当的回退。

Workbox 可以帮助您管理资源缓存和服务需求。它也是最常用的 Service Worker 库;54% 的移动网站都在使用它,并且它也用于许多构建工具和 CLI 中,包括 Angular CLI、Create-React-App 和 Vue CLI。大多数其他库和框架(如 Next.js)也都有插件。

54%

使用 Service Worker 的移动网站使用 Workbox 库

Workbox 模块

Workbox 包括多个 (在内部称为模块),每个模块都侧重于管理您的资源和 Service Worker 行为的不同方面。

Workbox 模块在不同的上下文中工作,例如

  • 在 Service Worker 上下文中:您导入所需的模块,并从 Service Worker 文件中使用它们,例如,帮助管理缓存和使用不同的策略来提供文件。
  • 在主 window 上下文中:帮助注册 Service Worker 并与其通信
  • 作为构建系统的一部分:例如,webpack,用于创建资源清单,甚至生成整个 Service Worker 等目的。

一些常用的模块包括

  • workbox-routing:当 Service Worker 拦截请求时,此模块会将这些请求路由到提供响应的不同函数;它是 fetch 事件处理程序的实现,如服务章节中所述。
  • workbox-strategies:一组运行时缓存策略,用于处理对请求的响应,例如 Cache First 和 Stale-While-Revalidate;它是 服务章节中提到的不同策略的实现。
  • workbox-precaching:它是 Service Worker 的 install 事件处理程序(也称为预缓存)中缓存文件的实现,如缓存章节中所述。借助此模块,您可以轻松地预缓存一组文件并有效地管理对这些资源的更新。我们将在更新章节中介绍更新资源。
  • workbox-expiration:它是一个与缓存策略一起使用的插件,用于根据缓存中的项目数或缓存请求的期限删除缓存的请求。它有助于管理您的缓存并设置每个缓存的时间和项目数限制。
  • workbox-window:一组旨在在 window 上下文中运行的模块,也就是说,在您的 PWA 网页内部。您可以简化 Service Worker 注册和更新过程,并实现 Service Worker 上下文和 window 上下文中运行的代码之间更轻松的通信。

使用 Workbox

Workbox 提供了不同的方式来集成到您的 PWA 中。您可以选择最适合您的应用架构的方式

  • Workbox CLI:一个命令行实用程序,用于生成完整的 Service Worker、注入预缓存清单或复制所需的 Workbox 文件。
  • Workbox Build:一个 npm 模块,用于生成完整的 Service Worker、注入预缓存清单和复制 Workbox 文件。它旨在与您自己的构建过程集成。
  • workbox-sw:一种从不使用构建过程的 CDN 加载 Workbox Service Worker 包的方式。

Workbox CLI 提供了一个向导,引导您完成创建 Service Worker 的过程。要运行向导,请在命令行中键入以下命令

npx workbox-cli wizard

Workbox CLI in action in a terminal

使用 Workbox 进行缓存和服务

Workbox 的常见用途是将路由和策略模块结合使用,以缓存和服务文件。

workbox-strategies 模块开箱即用地提供了资源和数据服务章节中讨论的缓存策略。

workbox-routing 模块有助于对传入 Service Worker 的请求进行排序,并将它们与缓存策略或函数匹配,以获取这些请求的响应。

在路由与策略匹配之后,Workbox 还提供了一种通过 workbox-cacheable-response 插件来过滤哪些响应将添加到缓存的功能。借助此插件,您可以例如仅缓存返回时未出错的响应。

以下代码示例使用 Cache First 策略(通过 CacheFirst 模块)来缓存和服务页面导航。

import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';

const pageStrategy = new CacheFirst({
  // Put all cached files in a cache named 'pages'
  cacheName: 'pages',
  plugins: [
    // Only requests that return with a 200 status are cached
    new CacheableResponsePlugin({
      statuses: [200],
    }),
  ],
});

该插件允许您利用 Workbox 的缓存和请求解析生命周期。在这里,CacheableResponsePlugin 用于仅缓存状态为 200 的请求,从而防止将错误请求保存到缓存中。

创建策略后,就该注册路由以使用它了。以下示例调用 registerRoute(),并将 Request 对象传递给其回调。如果 request.mode"navigate",它将使用 CacheFirst 策略(此处称为 pageStrategy),该策略在前面的代码示例中定义。

// Cache page navigations (HTML) with a Cache First strategy
registerRoute( ({ request }) => request.mode === 'navigate',
  pageStrategy );

阅读 Workbox 文档以获取更多示例和最佳实践。

离线回退

workbox-routing 模块还导出了 setCatchHandler(),用于在路由抛出错误时提供处理。您可以使用它来设置离线回退,以通知用户他们请求的路由当前不可用。

在这里,Workbox 和 Cache Storage API 的组合使用仅缓存策略提供了离线回退。首先,在 Service Worker 的安装生命周期中,打开 offline-fallbacks 缓存,并将离线回退数组添加到缓存中。

import { setCatchHandler } from 'workbox-routing';

// Warm the cache when the service worker installs
self.addEventListener('install', event => {
  const files = ['/offline.html']; // you can add more resources here
  event.waitUntil(
    self.caches.open('offline-fallbacks')
        .then(cache => cache.addAll(files))
  );
});

然后,在 setCatchHandler() 中,确定抛出错误的请求的目标,并打开 offline-fallbacks 缓存。如果目标是文档,则将离线回退的内容返回给用户。如果该内容不存在,或者目标不是文档(例如图像或样式表),则返回错误响应。您可以扩展此模式,不仅用于文档,还可以用于图像、视频、字体,以及您想要作为离线回退提供的任何内容。

// Respond with the fallback if a route throws an error
setCatchHandler(async (options) => {
  const destination = options.request.destination;
  const cache = await self.caches.open('offline-fallbacks');
  if (destination === 'document') {
    return (await cache.match('/offline.html')) || Response.error();
  }
  return Response.error();
});

配方

几种路由和缓存模式(如 NetworkFirst 导航和离线回退)非常常见,可以封装到可重用的配方中。查看 workbox-recipes,因为如果它们提供了适合您架构的解决方案,它们可能会对您有所帮助。它们通常作为一行代码提供,您需要将其添加到 Service Worker 的代码中。

缓存和更新资源

缓存资源还涉及更新它们。Workbox 可以帮助您以您认为最佳的方式更新您的资源。如果资源在服务器上发生更改,则可以保持更新,或者等到您拥有新版本的应用。您将在更新章节中了解有关更新的更多信息。

试用 Workbox

您可以立即使用以下代码实验室试用 Workbox

资源