本指南重点介绍了 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
配置选项更改此替换字符串。
导航路线变更
导航路线之前支持的两个选项 blacklist
和 whitelist
已重命名为 denylist
和 allowlist
。
workbox-routing
之前支持 registerNavigationRoute()
方法,该方法本质上执行了两项操作:
- 检测给定
fetch
事件是否具有'navigate'
的mode
。 - 如果已缓存,则无论导航到哪个网址,都会使用之前缓存的硬编码网址的内容响应该请求。
这是实现 App Shell 架构时常用的模式。
第二步(通过从缓存中读取生成响应)超出了我们认为 workbox-routing
的职责范围。我们认为,该功能应通过新方法 createHandlerBoundToURL()
作为 workbox-precaching
的一部分提供。此新方法可以与 workbox-routing
中的现有 NavigationRoute
类协同工作,以实现相同的逻辑。
如果您正在使用构建工具的“生成软件”中的 navigateFallback
选项模式,则会自动进行切换。如果您之前配置了 navigateFallbackBlacklist
或 navigateFallbackWhitelist
选项,请分别将其更改为 navigateFallbackDenylist
或 navigateFallbackAllowlist
。
如果您使用的是“注入清单”模式或仅自行编写服务工件,并且您的 Workbox v4 服务工件直接调用 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()
将为您处理。
从工作框策略中移除了 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()
。
我们意识到,必须监听两个潜在的传入消息来源会导致编写客户端代码过于复杂。此外,在某些浏览器中,服务工作器发送到客户端网页的 postMessage()
调用会自动缓冲,直到设置 message
事件监听器为止。Broadcast Channel API 不会缓冲,如果广播消息在客户端页面准备好接收之前发送,则会被丢弃。
出于这些原因,我们在 v5 中将 workbox-broadcast-update
更改为始终使用 postMessage()
。系统会将消息逐一发送到当前服务工件范围内的所有客户端页面。
为了适应这种新行为,您可以移除客户端网页中用于创建 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()
调用。
构建工具需要 Node.js v8 或更高版本
workbox-webpack-plugin
、workbox-build
或 workbox-cli
不再支持低于 v8 的 Node.js 版本。如果您运行的 Node.js 版本低于 8,请将运行时更新到受支持的版本。
workbox-webpack-plugin 需要 webpack v4 或更高版本
如果您使用的是 workbox-webpack-plugin
,请更新您的 webpack 设置,至少使用 webpack v4。
构建工具选项更新
一些 workbox-build
、workbox-cli
和 workbox-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-plugin
、workbox-build
、workbox-cli
)系统就会自动进行这项更改所有这些工具都会输出 Workbox 运行时本地自定义软件包,以及实现 Service Worker 逻辑所需的实际代码。在这种情况下,不再依赖于 workbox-sw
或 Workbox 的 CDN 副本。根据 inlineWorkboxRuntime
配置的值,Workbox 运行时将拆分为单独的文件(应与您的服务工件一起部署,如果设置为 false
,即默认值),或与服务工件逻辑一起内嵌(如果设置为 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 将自定义 Workbox 运行时包含在最终的服务工作器中,而不是从 CDN 加载运行时。
下面介绍了将一个 Service Worker 文件从 v4 升级到 v5 的之前和之后(包括改用 TypeScript),虽然并未涵盖所有重大更改。
获取帮助
我们预计大多数迁移都很简单。如果您遇到本指南未涵盖的问题,请在 GitHub 上提交问题,告知我们。