本指南重点介绍了 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网址() 的类似选项)。PrecacheController的install()和activate()方法现在只接受一个参数,该参数应分别设置为相应的InstallEvent或ActivateEvent。addRoute()方法已从PrecacheController中移除。取而代之的是,您可以使用新的PrecacheRoute类创建路线,然后进行注册。precacheAndRoute()方法已从PrecacheController中移除。(它仍然作为workbox-precaching模块导出的静态辅助方法存在。)之所以移除它,是因为可以改用PrecacheRoute。createMatchCalback()方法已从PrecacheController中移除。您可以改用新的PrecacheRoute。createHandler()方法已从PrecacheController中移除。您可以改用PrecacheController对象的strategy属性来处理请求。createHandler()静态导出已从workbox-precaching模块中移除。取而代之的是,开发者应构造PrecacheController实例并使用其strategy属性。- 在 
precacheAndRoute()中注册的路线现在是“真实”路线,在后台使用workbox-routing的Router类。如果您交错调用registerRoute()和precacheAndRoute(),这可能会导致路由的评估顺序不同。 
workbox-routing
setDefaultHandler() 方法现在接受与其适用的 HTTP 方法对应的可选第二个参数,默认为 'GET'。
- 如果您使用的是 
setDefaultHandler(),并且所有请求都是GET,则无需进行任何更改。 - 如果您有任何非 
GET的请求(POST、PUT等),setDefaultHandler()将不再导致这些请求匹配。 
构建配置
workbox-build 和 workbox-cli 中适用于 getManifest 和 injectManifest 模式的 mode 选项不受支持,已被移除。这不适用于 workbox-webpack-plugin,因为 workbox-webpack-plugin 在其 InjectManifest 插件中支持 mode。
构建工具需要 Node.js v10 或更高版本
workbox-webpack-plugin、workbox-build 或 workbox-cli 不再支持低于 v10 的 Node.js 版本。如果您运行的 Node.js 版本低于 v8,请将运行时更新到受支持的版本。
新改进
workbox-strategies
Workbox v6 引入了一种新的方式,让第三方开发者可以定义自己的 Workbox 策略。这样可确保第三方开发者能够以完全满足其需求的方式扩展 Workbox。
新的 Strategy 基类
在 v6 中,所有 Workbox 策略类都必须扩展新的 Strategy 基类。所有内置策略均已重写,以支持此功能。
Strategy 基类负责以下两项主要任务:
- 调用对所有策略处理程序通用的插件生命周期回调(例如,在它们启动、响应和结束时)。
 - 创建一个“处理程序”实例,该实例可以管理策略正在处理的每个个别请求的状态。
 
新的“handler”类
我们之前使用内部模块 fetchWrapper 和 cacheWrapper,它们(顾名思义)会将各种提取和缓存 API 封装到其生命周期钩子中。目前,插件之所以能够正常运行,就是依靠此机制,但此机制不会向开发者公开。
新的“handler”类 StrategyHandler 将公开这些方法,以便自定义策略可以调用 fetch() 或 cacheMatch(),并自动调用添加到策略实例中的所有插件。
借助此类,开发者还可以添加自己的自定义生命周期回调,这些回调可能因策略而异,并且可以与现有插件接口“正常运行”。
新的插件生命周期状态
在 Workbox v5 中,插件是无状态的。这意味着,如果针对 /index.html 的请求同时触发了 requestWillFetch 和 cachedResponseWillBeUsed 回调,这两个回调将无法相互通信,甚至不知道它们是由同一请求触发的。
在 v6 中,所有插件回调还会传递一个新的 state 对象。此状态对象将是此特定插件对象和此特定策略调用(即对 handle() 的调用)所特有的。这样,开发者就可以编写插件,其中一个回调可以根据同一插件中的另一个回调执行的操作来有条件地执行某些操作(例如,计算运行 requestWillFetch 和 fetchDidSucceed 或 fetchDidFail 之间的时间差)。
新的插件生命周期回调
添加了新的插件生命周期回调,以便开发者充分利用插件生命周期状态:
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 的“正常”事件。这样一来,关心此区别的开发者仍然可以检测到此区别,而不需要知道此区别的开发者可以忽略此属性。
更简洁的“为用户提供网页重新加载”方案
得益于上述两项变更,“为用户提供页面重新加载”方案可以简化为:
// v6:
<script type="module">
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.0.0-alpha.1/workbox-window.prod.mjs';
  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    const showSkipWaitingPrompt = () => {
      // This assumes a hypothetical createUIPrompt() method with
      // onAccept and onReject callbacks:
      const prompt = createUIPrompt({
        onAccept: () => {
          wb.addEventListener('controlling', () => {
            window.location.reload();
          });
          // This will postMessage() to the waiting service worker.
          wb.messageSkipWaiting();
        },
        onReject: () => {
          prompt.dismiss();
        },
      });
    };
    // Listening for externalwaiting is no longer needed.
    wb.addEventListener('waiting', showSkipWaitingPrompt);
    wb.register();
  }
</script>
workbox-routing
系统会将一个新的布尔值参数 sameOrigin 传递给 workbox-routing 中使用的 matchCallback 函数。如果请求的网址是同源网址,则将其设置为 true;否则将其设置为 false。
这样可以简化一些常见的样板代码:
// In v5:
registerRoute(
  ({url}) =>
    url.origin === self.location.origin && url.pathname.endsWith('.png'),
  new StaleWhileRevalidate({cacheName: 'local-png'})
);
// In v6:
registerRoute(
  ({sameOrigin, url}) => sameOrigin && url.pathname.endsWith('.png'),
  new StaleWhileRevalidate({cacheName: 'local-png'})
);
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 进行响应:
import {PrecacheFallbackPlugin, precacheAndRoute} from 'workbox-precaching';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';
// Ensure that /offline.html is part of your precache manifest!
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
  ({request}) => request.mode === 'navigate',
  new NetworkOnly({
    plugins: [
      new PrecacheFallbackPlugin({
        fallbackURL: '/offline.html',
      }),
    ],
  })
);
运行时缓存中的 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 上提交问题,告知我们。