从 Workbox v4 迁移到 v5

本指南重点介绍 Workbox v5 中引入的破坏性更改,并举例说明了从 Workbox v4 升级时需要做出哪些更改。

重大更改

重命名的插件类

许多 Workbox v4 软件包都包含名为 Plugin 的类。在 v5 中,这些类已重命名,以遵循模式软件包标识符 + Plugin

  • BackgroundSyncPlugin
  • BroadcastUpdatePlugin
  • CacheableResponsePlugin
  • ExpirationPlugin
  • RangeRequestsPlugin

无论您是通过模块导入还是 workbox.* 命名空间使用这些类,此重命名都适用。

默认预缓存清单替换点

以前,在“注入清单”模式下使用其中一个构建工具时,系统会检查源 Service Worker 文件是否存在 precacheAndRoute([]),并将空数组 [] 用作注入预缓存清单时点的占位符。

在 Workbox v5 中,替换逻辑已更改,现在 self.__WB_MANIFEST 默认用作注入点。

// v4:
precacheAndRoute([]);

// v5:
precacheAndRoute(self.__WB_MANIFEST);

此讨论所述,我们认为此变更可以提供更简单的体验,同时让开发者能够更好地控制注入的清单在自定义 Service Worker 代码中的使用方式。如果需要,您可以通过 injectionPoint 配置选项更改此替换字符串。

导航路线以前支持的两个选项 blacklistwhitelist 已重命名为 denylistallowlist

workbox-routing 之前支持 registerNavigationRoute() 方法,该方法会在后台执行两项操作:

  1. 检测给定fetch事件是否具有 'navigate'mode
  2. 如果是,使用之前缓存的硬编码网址的内容响应该请求,无论要转到哪个网址。

这是实现 App Shell 架构时使用的常见模式。

第二步是通过从缓存中读取数据来生成响应,不在我们看来的 workbox-routing 职责范围内。相反,我们通过新方法 createHandlerBoundToURL() 将其视为 workbox-precaching 的一部分。这种新方法可与 workbox-routing 中的现有 NavigationRoute 类结合使用,以实现相同的逻辑。

如果您在构建工具的某个“生成软件”模式下使用 navigateFallback 选项,则切换会自动进行。如果您之前配置了 navigateFallbackBlacklistnavigateFallbackWhitelist 选项,请分别将其更改为 navigateFallbackDenylistnavigateFallbackAllowlist

如果您使用“注入清单”模式或仅自行编写 Service Worker,并且您的 Workbox v4 Service Worker 直接调用 registerNavigationRoute(),那么您将必须更改代码以获得等效的行为。

// v4:
import {getCacheKeyForURL} from 'workbox-precaching';
import {registerNavigationRoute} from 'workbox-routing';

const appShellCacheKey = getCacheKeyForURL('/app-shell.html');
registerNavigationRoute(appShellCacheKey, {
  whitelist: [...],
  blacklist: [...],
});

// v5:
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [...],
  denylist: [...],
});
registerRoute(navigationRoute);

您无需再调用 getCacheKeyForURL(),因为 createHandlerBoundToURL() 会为您处理。

从 workbox-strategies 中移除了 makeRequest()

调用 makeRequest() 基本等同于对其中一个 workbox-strategy 类调用 handle()。这两种方法之间的区别非常小,以至于保留它们没有意义。调用 makeRequest() 的开发者应该能够改为使用 handle(),而无需进行任何其他更改:

// v4:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.makeRequest({event, request});

// v5:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.handle({event, request});

在 v5 中,handle()request 视为必需参数,并且不会回退为使用 event.request。确保在调用 handle() 时传入有效的请求。

workbox-broadcast-update 始终使用 postMessage()

在 v4 中,workbox-broadcast-update 库将默认使用 Broadcast Channel API 发送消息(如果受支持),并仅在广播频道不受支持时回退到使用 postMessage()

我们意识到,必须监听两个潜在传入消息来源使得编写客户端代码过于复杂。此外,在某些浏览器上,从 Service Worker 发送到客户端页面的 postMessage() 调用会自动缓冲,直到设置 message 事件监听器为止。广播频道 API 没有缓冲,如果在客户端页面准备好接收广播消息之前,广播消息会被丢弃。

由于这些原因,我们已将 workbox-broadcast-update 更改为在 v5 中始终使用 postMessage()。消息将逐个发送至当前 Service Worker 作用域内的所有客户端页面。

为了适应这种新行为,您可以移除创建了 BroadcastChannel 实例的客户端页面中的任何代码,并改为在 navigator.serviceWorker 上设置 message 事件监听器:

// v4:
const updatesChannel = new BroadcastChannel('api-updates');
updatesChannel.addEventListener('message', event => {
  const {cacheName, updatedUrl} = event.data.payload;
  // ... your code here ...
});

// v5:
// This listener should be added as early as possible in your page's lifespan
// to ensure that messages are properly buffered.
navigator.serviceWorker.addEventListener('message', event => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;
    // ... your code here ...
  }
});

workbox-window 用户不需要进行任何更改,因为它的内部逻辑已更新为监听 postMessage() 调用。

Build Tools 需要 Node.js v8 或更高版本

workbox-webpack-pluginworkbox-buildworkbox-cli 不再支持 v8 之前的 Node.js 版本。如果您运行的 Node.js 版本低于 8,请将运行时更新为受支持的版本

workbox-webpack-plugin 需要 webpack v4 或更高版本

如果您使用的是 workbox-webpack-plugin,请更新您的 webpack 设置以至少使用 webpack v4。

Build Tool 选项翻新

一些 workbox-buildworkbox-cliworkbox-webpack-plugin 配置参数不再受支持。例如,generateSW 将始终为您创建本地 Workbox 运行时软件包,因此 importWorkboxFrom 选项将不再有意义。

请参阅相关工具的文档,了解支持的选项列表。

从 workbox-build 中移除了 generateSWString

generateSWString 模式已从 workbox-build 中移除。由于此功能主要供 workbox-webpack-plugin 在内部使用,我们预计其影响微乎其微。

可选更改

使用模块导入

虽然此变更 a) 是可选的,并且 b) 在使用 Workbox v4 时可以实现,但我们预计在迁移到 v5 期间的最大变化是,您可以通过导入 Workbox 的模块创建自己的捆绑 Service Worker。除了在 Service Worker 顶部调用 importScripts('/path/to/workbox-sw.js') 并通过 workbox.* 命名空间使用 Workbox,此方法可作为替代方法。

如果您在“生成软件”模式下使用其中一个构建工具(workbox-webpack-pluginworkbox-buildworkbox-cli),系统会自动为您进行此更改。所有这些工具都将输出一个本地自定义 Workbox 运行时捆绑包,以及实现 Service Worker 逻辑所需的实际代码。在这种情况下,不再依赖于 workbox-sw 或 Workbox 的 CDN 副本。根据 inlineWorkboxRuntime 配置的值,Workbox 运行时将拆分成一个单独的文件,应随 Service Worker 一起部署(设置为 false,即默认值时),或与 Service Worker 逻辑一起内嵌(设置为 true 时)。

如果您在“注入清单”模式下使用构建工具,或者根本没有使用 Workbox 的构建工具,可参阅现有的将捆绑器 (webpack/Rollup) 与 Workbox 搭配使用指南,详细了解如何创建自己的 Workbox 运行时捆绑包。

我们在编写 v5 的文档和示例时假设采用模块导入语法,但 Workbox v5 将继续支持 workbox.* 命名空间。

读取预缓存的响应

一些开发者需要直接从缓存中读取预缓存的响应,而不是通过 precacheAndRoute() 方法隐式使用它们。v4 中的一种常见模式是先获取特定于预缓存资源的当前版本的缓存键,然后将该键连同预缓存的缓存名称一起传递给 caches.match() 以获取 Response

为了简化此流程,v5 中的 workbox-precaching 支持一种新的等效方法 matchPrecache()

// v4:
import {cacheNames} from 'workbox-core';
import {getCacheKeyForURL} from 'workbox-precaching';

const cachedResponse = await caches.match(
  getCacheKeyForURL(`/somethingPrecached`),
  {
    cacheName: cacheNames.precache,
  }
);

// v5:
import {matchPrecache} from 'workbox-precaching';

const cachedResponse = await matchPrecache(`/somethingPrecached`);

TypeScript 采用

在 v5 中,Workbox 运行时库使用 TypeScript 编写。虽然我们会继续发布经过转译的 JavaScript 模块和捆绑包,以让尚未采用 TypeScript 的开发者也能从中受益,但如果您使用的是 TypeScript,则可以直接从 Workbox 项目获得准确、始终最新的类型信息。

迁移示例

此提交说明迁移过程相当复杂,带有内联注释。它使用 Rollup 在最终 Service Worker 中包含自定义 Workbox 运行时,而不是从 CDN 加载运行时。

虽然并未涵盖所有破坏性更改,但下文介绍了将一个 Service Worker 文件从 v4 升级到 v5 的之前之后,包括改用 TypeScript 的方法。

获取帮助

我们预计大多数迁移都是非常简单的。如果您遇到本指南未涵盖的问题,请在 GitHub 上提交问题告知我们。