从 Workbox v5 迁移到 v6

本指南重点介绍了 Workbox v6 中引入的重大变更,并通过示例说明了从 Workbox v5 升级时需要进行哪些更改。

重大变更

workbox-core

workbox-core 中的 skipWaiting() 方法将不再添加 install 处理脚本,而等同于仅调用 self.skipWaiting()

从现在开始,请改用 self.skipWaiting(),因为 skipWaiting() 可能会在 Workbox v7 中被移除。

workbox-precaching

  • 与 HTTP 重定向对应的网址的跨源 HTML 文档不能再用于通过 workbox-precaching 满足导航请求。这种情况通常并不常见。
  • 现在,在查找指定请求的预缓存响应时,workbox-precaching 会忽略 fbclid 网址查询参数。
  • PrecacheController 构造函数现在接受具有特定属性的对象作为参数,而不是字符串。此对象支持以下属性:cacheName(与 v5 中传递给构造函数的字符串具有相同的用途)、plugins(替换 v5 中的 addPlugins() 方法)和 fallbackToNetwork(替换传递给 createHandler() 和 v5 中的 `createHandlerBoundTo网址() 的类似选项)。
  • PrecacheControllerinstall()activate() 方法现在只接受一个参数,该参数应分别设置为相应的 InstallEventActivateEvent
  • addRoute() 方法已从 PrecacheController 中移除。取而代之的是,您可以使用新的 PrecacheRoute 类创建路线,然后进行注册。
  • precacheAndRoute() 方法已从 PrecacheController 中移除。(它仍作为由 workbox-precaching 模块导出的静态辅助方法而存在。)之所以移除它,是因为可以改用 PrecacheRoute
  • createMatchCalback() 方法已从 PrecacheController 中移除。您可以改用新的 PrecacheRoute
  • createHandler() 方法已从 PrecacheController 中移除。您可以改用 PrecacheController 对象的 strategy 属性来处理请求。
  • createHandler() 静态导出已从 workbox-precaching 模块中移除。取而代之的是,开发者应构造 PrecacheController 实例并使用其 strategy 属性。
  • precacheAndRoute() 中注册的路线现在是“真实”路线,在后台使用 workbox-routingRouter 类。如果您交错调用 registerRoute()precacheAndRoute(),这可能会导致路由的评估顺序不同。

workbox-routing

setDefaultHandler() 方法现在接受与其适用的 HTTP 方法相对应的可选第二个参数,默认为 'GET'

  • 如果您使用 setDefaultHandler() 且所有请求均为 GET,则无需进行任何更改。
  • 如果您有任何非 GET 的请求(POSTPUT 等),setDefaultHandler() 将不再导致这些请求匹配。

构建配置

workbox-buildworkbox-cli 中适用于 getManifestinjectManifest 模式的 mode 选项不受支持,已被移除。这不适用于 workbox-webpack-plugin,因为后者在其 InjectManifest 插件中支持 mode

构建工具需要 Node.js v10 或更高版本

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

新改进

工作箱策略

Workbox v6 引入了一种新的方式,让第三方开发者可以定义自己的 Workbox 策略。这样可确保第三方开发者能够以完全满足其需求的方式扩展 Workbox。

新的 Strategy 基类

在 v6 中,所有 Workbox 策略类都必须扩展新的 Strategy 基类。所有内置策略都已重写,以支持此功能。

Strategy 基类负责两项主要任务:

  • 调用适用于所有策略处理脚本的常见插件生命周期回调(例如,在它们启动、响应和结束时)。
  • 创建一个“处理程序”实例,该实例可以管理策略正在处理的每个个别请求的状态。

新的“handler”类

我们之前使用内部模块 fetchWrappercacheWrapper,它们(顾名思义)会将各种提取和缓存 API 封装到其生命周期钩子中。此机制目前可让插件正常运行,但尚未向开发者公开。

新的“handler”类 StrategyHandler 将公开这些方法,以便自定义策略可以调用 fetch()cacheMatch(),并自动调用添加到策略实例中的所有插件。

借助此类,开发者还可以添加可能特定于其策略的自定义生命周期回调,并且这些回调会“直接”与现有插件接口配合使用。

新插件生命周期状态

在 Workbox v5 中,插件是无状态的。这意味着,如果针对 /index.html 的请求同时触发了 requestWillFetchcachedResponseWillBeUsed 回调,这两个回调将无法相互通信,甚至不知道它们是由同一请求触发的。

在 v6 中,系统还会向所有插件回调传递一个新的 state 对象。此状态对象将是此特定插件对象和此特定策略调用(即对 handle() 的调用)所特有的。这样,开发者就可以编写插件,其中一个回调可以根据同一插件中的另一个回调执行的操作来有条件地执行某些操作(例如,计算运行 requestWillFetchfetchDidSucceedfetchDidFail 之间的时间差)。

新增插件生命周期回调

添加了新的插件生命周期回调,以便开发者充分利用插件生命周期状态:

  • handlerWillStart:在任何处理脚本逻辑开始运行之前调用。此回调可用于设置初始处理程序状态(例如记录开始时间)。
  • handlerWillRespond:在策略 handle() 方法返回响应之前调用。您可以使用此回调在将响应返回给路由处理程序或其他自定义逻辑之前修改该响应。
  • handlerDidRespond:在策略的 handle() 方法返回响应后调用。此回调可用于记录任何最终响应详细信息,例如其他插件进行更改后的信息。
  • handlerDidComplete:在通过调用此策略向事件添加的所有延长生命周期 promise 都已解决后调用。此回调可用于报告需要等待处理程序完成才能计算的任何数据(例如缓存命中状态、缓存延迟时间、网络延迟时间)。
  • handlerDidError:如果处理脚本无法从任何来源提供有效响应,则调用此方法。此回调可用于提供“后备”内容,作为网络错误的替代方案。

实现自己的自定义策略的开发者无需担心自己调用这些回调;这一切都由新的 Strategy 基类处理。

为处理程序提供更准确的 TypeScript 类型

各种回调方法的 TypeScript 定义已标准化。这应该会为使用 TypeScript 并编写自己的代码来实现或调用处理程序的开发者带来更好的体验。

workbox-window

新的 messageSkipWaiting() 方法

workbox-window 模块中添加了新方法 messageSkipWaiting(),以简化告知“等待中”服务工作器激活的过程。这带来了一些改进:

  • 它会使用事实上的标准消息正文 {type: 'SKIP_WAITING'} 调用 postMessage(),Workbox 生成的服务工件会检查该消息正文,以触发 skipWaiting()
  • 它会选择正确的“等待”服务工件来发布此消息,即使该服务工件与 workbox-window 注册的服务工件不同也是如此。

移除了“external”事件,改用 isExternal 属性

workbox-window 中的所有“外部”事件均已移除,取而代之的是将 isExternal 属性设为 true 的“正常”事件。这样一来,关心此区别的开发者仍然可以检测到此区别,而不需要了解此区别的开发者可以忽略此属性。

更简洁的“为用户提供网页重新加载”方案

得益于以上两项更改,“向用户提供页面重新加载”方案可以简化:

MULTI_LINE_CODE_PLACEHOLDER_0

workbox-routing

系统会将一个新的布尔值参数 sameOrigin 传递给 workbox-routing 中使用的 matchCallback 函数。如果请求的网址是同源网址,则将其设置为 true;否则将其设置为 false。

这样可以简化一些常见的样板代码:

MULTI_LINE_CODE_PLACEHOLDER_1

workbox-expiration 中的 matchOptions

现在,您可以在 workbox-expiration 中设置 matchOptions,然后将其作为 CacheQueryOptions 传递给底层 cache.delete() 调用。(大多数开发者都不需要执行此操作。)

workbox-precaching

使用 workbox-strategies

workbox-precaching 已重写,以使用 workbox-strategies 作为基础。这应该不会导致任何破坏性更改,并且应该可以使两个模块访问网络和缓存的方式长期保持更好的一致性。

预缓存现在会逐个处理条目,而不是批量处理

workbox-precaching 已更新,以便一次只请求并缓存预缓存清单中的一条条目,而不是尝试一次请求并缓存所有条目(由浏览器自行确定如何节流)。

这应该会降低预缓存期间发生 net::ERR_INSUFFICIENT_RESOURCES 错误的可能性,还会降低预缓存和 Web 应用发出的并发请求之间的带宽争用。

PrecacheFallbackPlugin 可让您更轻松地实现离线回退

workbox-precaching 现在包含一个 PrecacheFallbackPlugin,用于实现 v6 中新增的 handlerDidError 生命周期方法。

这样,当无法获取响应时,您就可以轻松地将预缓存的网址指定为给定策略的“后备”。插件将负责为预缓存的网址正确构造正确的缓存键,包括所需的任何修订版本参数。

以下示例展示了在 NetworkOnly 策略无法为导航请求生成响应(换句话说,显示自定义离线 HTML 网页)时,使用该策略以预缓存的 /offline.html 进行响应:

MULTI_LINE_CODE_PLACEHOLDER_2

运行时缓存中的 precacheFallback

如果您使用 generateSW 为您创建服务工件,而不是手动编写服务工件,则可以使用 runtimeCaching 中的新 precacheFallback 配置选项来实现相同的目的:

{
  // ... other generateSW config options...
  runtimeCaching: [{
    urlPattern: ({request}) => request.mode === 'navigate',
    handler: 'NetworkOnly',
    options: {
      precacheFallback: {
        // This URL needs to be included in your precache manifest.
        fallbackURL: '/offline.html',
      },
    },
  }],
}

获取帮助

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