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:一组运行时缓存策略,用于处理请求响应,例如先缓存并在重新验证时过时;而是“投放”一章中提到的不同策略的实施方式。
  • workbox-precaching:它是 Service Worker 的 install 事件处理程序中缓存文件的实现(也称为预缓存),如缓存一章中所述。借助此模块,您可以轻松预缓存一组文件,并高效地管理这些资产的更新。我们将在“更新”一章中介绍如何更新资产。
  • workbox-expiration:这是一个与缓存策略搭配使用的插件,用于根据缓存中的项数或缓存请求的存在时间移除缓存的请求。它有助于管理您的缓存,并可设置时间和每个缓存中的内容数量限制。
  • workbox-window:一组模块,用于在窗口上下文中(即在 PWA 网页内)运行。您可以简化 Service Worker 注册和更新过程,并使在 Service Worker 上下文中运行的代码与窗口上下文之间的通信变得更轻松。

使用 Workbox

Workbox 提供了多种集成到 PWA 中的方法。您可以选择最适合您的应用架构的方案:

  • Workbox CLI:一种命令行实用程序,可以生成完整的 Service Worker、注入预缓存清单或复制所需的 Workbox 文件。
  • Workbox Build:用于生成完整 Service Worker、注入预缓存清单并复制 Workbox 文件的 npm 模块。这意味着需要与您自己的构建流程集成。
  • workbox-sw:一种从不使用构建流程的 CDN 加载 Workbox Service Worker 软件包的方法。

Workbox CLI 提供了一个向导,可引导您创建 Service Worker。要运行该向导,请在命令行中键入以下内容:

npx workbox-cli wizard

Workbox CLI 在终端中的运行情况

使用 Workbox 进行缓存和传送

Workbox 的一个常见用途是结合使用路由模块和策略模块,以缓存和提供文件。

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

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

在将路由与策略匹配后,Workbox 还通过 workbox-cacheable-response 插件过滤将哪些响应添加到缓存中。例如,使用此插件,您可以仅缓存未出现错误的响应。

以下代码示例使用缓存优先策略(通过 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

您可以使用以下 Codelab 立即体验 Workbox:

资源