随着 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 进行缓存和服务
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