随着 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:一种 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 插件过滤将添加到缓存中的响应。例如,借助此插件,您可以仅缓存返回而不出现错误的响应。
以下代码示例使用缓存优先策略(通过 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();
});
Recipes
多种路由和缓存模式(如 NetworkFirst
导航和离线回退)非常常见,因此可以封装到可重复使用的方案中。选中 workbox-recipes,因为它们如果提供了适合您架构的解决方案,则会对您有所帮助。它们通常以一行代码的形式提供,您需要添加到 Service Worker 的代码中。
缓存和更新资产
缓存资产还需要更新资产。Workbox 可帮助您以您确定的最佳方式更新资源。如果它们在服务器上发生更改,系统可能会将它们及时告知您,或者等到您的应用有新版本时再进行更新。如需详细了解如何更新,请参阅“更新”章节。
使用 Workbox 畅玩
您可以使用以下 Codelab 立即体验 Workbox: