本指南将重点介绍 Workbox v3 中引入的破坏性更改,并通过示例说明从 Workbox v2 设置升级时需要做出哪些更改。
如果您目前使用的是旧版 sw-precache/sw-toolbox 组合,并希望首次改用 Workbox,可参阅其他迁移指南,参阅相应的迁移指南。
v3 背景
Workbox 的 v3 版本对现有代码库进行了重大重构。总体目标是:
- 尽可能减小 Workbox 的大小。下载和执行的 Service Worker 运行时代码量减少了。系统会在运行时导入您所使用的特定功能的代码,而不是让所有用户都能使用单体式软件包。
 - Workbox 有 CDN。我们提供完全受支持的、基于 Google Cloud Storage 的 CDN 托管,作为访问 Workbox 运行时库的规范选项,让您可以更轻松地启动和运行 Workbox。
 - 更好的调试和日志记录功能。调试和日志记录体验得到了极大改进。每当从 
localhost源使用 Workbox,并且从正式版 build 中删除所有日志记录和断言时,调试日志默认处于启用状态。
 - 改进了 webpack 插件。
workbox-webpack-plugin与 webpack 构建流程更紧密地集成,因此当您希望预缓存构建流水线中的所有资源时,可实现零配置的用例。 
为了实现这些目标,并清理之前的界面中令人感到尴尬或导致反模式的某些方面,需要在 v3 版本中引入一些破坏性更改。
重大变更
构建配置
以下变更会影响我们共用一组通用配置选项的所有构建工具(workbox-build、workbox-cli、workbox-webpack-plugin)的行为。
'fastest'处理程序名称之前有效,并且在配置runtimeCaching时被视为'staleWhileRevalidate'的别名。此 ID 已失效,开发者应改为直接使用'staleWhileRevalidate'。- 更新了多个 
runtimeCaching.options属性名称,并进行了额外的参数验证,如果使用无效配置会导致构建失败。如需查看当前支持的选项列表,请参阅runtimeCaching的文档。 
workbox-background-sync
maxRetentionTime配置参数现在被解释为分钟数,而不是毫秒数。- 现在有一个表示队列名称的必需字符串,在构建插件或独立类时,必须将其作为第一个参数传入。(之前,它是作为选项的属性传入的)。如需了解更新后的 API Surface,请参阅文档。
 
workbox-broadcast-cache-update
- 现在有一个表示频道名称的必需字符串,在构建插件或独立类时,必须将其作为第一个参数传入。
 
例如,在 v2 中,您需要按如下方式初始化 Plugin 类:
new workbox.broadcastCacheUpdate.BroadcastCacheUpdatePlugin({
  channelName: 'cache-updates',
  headersToCheck: ['etag'],
});
v3 中的等效用法如下:
new workbox.broadcastUpdate.Plugin('cache-updates', {headersToCheck: ['etag']});
如需了解更新后的 API Surface,请参阅文档。
workbox-build
- 默认情况下,
glob模式匹配现在使用选项follow: true(后跟符号链接)和strict: true(对“异常”错误的容忍度较低)执行。通过在 build 配置中设置globFollow: false和/或globStrict: false,您可以停用其中任一功能并恢复之前的行为。 workbox-build中的函数都会在返回的响应中返回一个附加属性warnings。现在允许在 v2 中被视为严重错误的一些场景,但通过warnings(一个字符串数组)进行报告。
在 v2 中,您可以调用 generateSW,如下所示:
const workboxBuild = require('workbox-build');
workboxBuild.generateSW({...})
  .then(({count, size}) => console.log(`Precached ${count} files, totaling ${size} bytes.`))
  .catch((error) => console.error(`Something went wrong: ${error}`));
虽然您可以在 v3 中使用相同的代码,但建议检查是否存在任何 warnings 并记录它们:
const workboxBuild = require('workbox-build');
workboxBuild.generateSW({...})
  .then(({count, size, warnings}) => {
    for (const warning of warnings) {
      console.warn(warning);
    }
    console.log(`Precached ${count} files, totalling ${size} bytes.`);
  })
  .catch((error) => console.error(`Something went wrong: ${error}`));
- 在 v2 中编写自己的自定义 
ManifestTransform函数的开发者需要在对象中返回清单数组(即,您应该使用return {manifest: manifestArray};,而不是return manifestArray;)。mThis 可让您的插件添加一个可选的warnings属性,该属性应该是包含非严重警告信息的字符串数组。 
如果您使用 v2 编写自定义 ManifestTransform,则代码如下所示:
const cdnTransform = manifestEntries => {
  return manifestEntries.map(entry => {
    const cdnOrigin = 'https://example.com';
    if (entry.url.startsWith('/assets/')) {
      entry.url = cdnOrigin + entry.url;
    }
    return entry;
  });
};
具有 v3 等效项:
const cdnTransform = manifestEntries => {
  const manifest = manifestEntries.map(entry => {
    const cdnOrigin = 'https://example.com';
    if (entry.url.startsWith('/assets/')) {
      entry.url = cdnOrigin + entry.url;
    }
    return entry;
  });
  return {manifest, warnings: []};
};
getFileManifestEntries()函数已重命名为getManifest(),返回的 promise 现在包含有关预缓存网址的其他信息。
v2 中的如下代码:
const manifestEntries = await workboxBuild.getFileManifestEntries({...});
在 v3 中可以重写为:
const {manifestEntries, count, size, warnings} = await workboxBuild.getManifest({...});
// Use manifestEntries like before.
// Optionally, log the new info returned in count, size, warnings.
- 移除了 
generateFileManifest()函数。建议开发者改为调用getManifest(),并使用其响应以适当的格式将数据写入磁盘。 
workbox-cache-expiration
- 插件 API 仍保持不变,大多数开发者最终都将使用该模式。不过,API 发生了重大变化,这会影响将它作为独立类使用的开发者。如需了解更新后的 API Surface,请参阅文档。
 
workbox-cli
开发者可以使用 --help 标志运行 CLI,以获取所有受支持的参数。
- 不再支持在二进制脚本中使用 
workbox-cli别名。二进制文件现在只能以workbox的形式访问。 - v2 命令 
generate:sw和inject:manifest在 v3 中已重命名为generateSW和injectManifest。 - 在 v2 中,系统假定默认配置文件(未明确提供配置文件时使用)是当前目录中的 
workbox-cli-config.js。在 v3 中,为workbox-config.js。 
总的来说,这意味着在 v2 中:
$ workbox inject:manifest
运行“注入清单”构建流程,使用从 workbox-cli-config.js 读取的配置,在 v3 中构建:
$ workbox injectManifest
会执行相同的操作,但从 workbox-config.js 读取配置。
工作箱预缓存
precache()方法之前会执行缓存修改并设置路由以提供缓存条目。现在,precache()仅修改缓存条目,并且已公开一个新方法addRoute(),用于注册一个路由以提供这些缓存的响应。如果开发者需要之前的二合一功能,可以改用调用precacheAndRoute()。- 过去通过 
WorkboxSW构造函数配置的多个选项现在作为options形参传入workbox.precaching.precacheAndRoute([...], options)中。参考文档中列出了这些选项的默认值(如果未配置)。 - 默认情况下,系统会自动检查没有任何文件扩展名的网址是否与包含 
.html扩展名的缓存条目匹配。例如,如果针对/path/to/index(未预缓存)发出请求,并且存在针对/path/to/index.html的预缓存条目,则系统会使用该预缓存条目。开发者可以在将选项传递到workbox.precaching.precacheAndRoute()时设置{cleanUrls: false}来停用此新行为。 workbox-broadcast-update将不再自动配置为公布预缓存资产的缓存更新。
以下代码(在 v2 中):
const workboxSW = new self.WorkboxSW({
  directoryIndex: 'index.html',
  ignoreUrlParametersMatching: [/^utm_/],
  precacheChannelName: 'precache-updates',
});
workboxSW.precache([...]);
具有 v3 等效项:
workbox.precaching.addPlugins([
    new workbox.broadcastUpdate.Plugin('precache-updates')
]);
workbox.precaching.precacheAndRoute([...], {
  cleanUrls: false,
  directoryIndex: 'index.html',
  ignoreUrlParametersMatching: [/^utm_/],
});
工作箱路由
- 之前通过 WorkboxSW 对象的 
workbox.router.*命名空间使用workbox-routing的开发者需要切换到新的命名空间workbox.routing.*。 - 现在,系统会按照“先注册成功”的顺序评估路线。这与 v2 中使用的 
Route计算顺序相反,其中最后注册的Route优先。 ExpressRoute类,以及对“Express-style”的支持通配符已移除。这会大幅缩减workbox-routing的大小。用作workbox.routing.registerRoute()第一个参数的字符串现在将被视为完全匹配。通配符或部分匹配应由RegExp处理,使用与请求网址的部分或全部匹配的任何RegExp均可触发路由。- 移除了 
Router类的addFetchListener()辅助方法。开发者可以明确添加自己的fetch处理程序,也可以使用workbox.routing提供的接口(该接口会为开发者隐式创建fetch处理程序)。 - 移除了 
registerRoutes()和unregisterRoutes()方法。针对单个Route运行的这些方法的版本保持不变,需要一次性注册或取消注册多个路由的开发者应改为对registerRoute()或unregisterRoute()进行一系列调用。 
以下代码(在 v2 中):
const workboxSW = new self.WorkboxSW();
workboxSW.router.registerRoute(
  '/path/with/.*/wildcard/',
  workboxSW.strategies.staleWhileRevalidate()
);
workboxSW.router.registerRoute(
  new RegExp('^https://example.com/'),
  workboxSW.strategies.networkFirst()
);
具有 v3 等效项:
workbox.routing.registerRoute(
  new RegExp('^https://example.com/'),
  workbox.strategies.networkFirst()
);
workbox.routing.registerRoute(
  new RegExp('^/path/with/.*/wildcard'),
  workbox.strategies.staleWhileRevalidate()
);
workbox-strategies(以前称为“workbox-runtime-caching”)
workbox-runtime-caching模块现已正式更名为workbox-strategies,并已采用新名称发布于npm。- 在策略中使用缓存过期时间而不同时提供缓存名称将失效。在 v2 中,可以做到以下几点:
 
workboxSW.strategies.staleWhileRevalidate({
  cacheExpiration: {maxEntries: 50},
});
这会导致默认缓存中的条目过期,这属于意外情况。在 v3 中,缓存名称 为必填项:
workboxSW.strategies.staleWhileRevalidate({
  cacheName: 'my-cache',
  plugins: [new workbox.expiration.Plugin({maxEntries: 50})],
});
cacheWillMatch生命周期方法已重命名为cachedResponseWillBeUsed。开发者应该不会轻易看到这项更改,除非他们自己编写了能够响应cacheWillMatch的插件。- 配置策略时用于指定插件的语法已经更改。每个插件都需要在策略配置的 
plugins属性中明确列出。 
以下代码(在 v2 中):
const workboxSW = new self.WorkboxSW();
const networkFirstStrategy = workboxSW.strategies.networkFirst({
  cacheName: 'my-cache',
  networkTimeoutSeconds: 5,
  cacheExpiration: {
    maxEntries: 50,
  },
  cacheableResponse: {
    statuses: [0, 200],
  },
});
具有 v3 等效项:
const networkFirstStrategy = workbox.strategies.networkFirst({
  cacheName: 'my-cache',
  networkTimeoutSeconds: 5,
  plugins: [
    new workbox.expiration.Plugin({maxEntries: 50}),
    new workbox.cacheableResponse.Plugin({statuses: [0, 200]}),
  ],
});
有关详情,请参阅“使用插件”指南。
Workbox-sw
- 在后台,
workbox-sw已被重写为轻量级“加载器”接口,该接口需要进行一些基本配置,并负责提取运行时所需的其他模块。开发者不会构建WorkboxSW类的新实例,而是与在全局命名空间中自动公开的现有实例进行交互。 
之前是在 v2 中:
importScripts('<path to workbox-sw>/importScripts/workbox-sw.prod.v2.1.3.js');
const workbox = new WorkboxSW({
  skipWaiting: true,
  clientsClaim: true,
  // etc.
});
workbox.router.registerRoute(...);
在 v3 中,您只需导入 workbox-sw.js 脚本,即可自动在全局命名空间中以 workbox 的形式提供可供使用的实例:
importScripts('<path to workbox-sw>/3.0.0/workbox-sw.js');
// workbox is implicitly created and ready for use.
workbox.routing.registerRoute(...);
skipWaiting和clientsClaim不再是传递给WorkboxSW构造函数的选项。而是将它们更改为了workbox.clientsClaim()和workbox.skipWaiting()方法。- 之前在 v2 构造函数中支持的 
handleFetch选项在 v3 中不再受支持。如果开发者需要类似功能来测试其 Service Worker,而不调用任何提取处理程序,则可以使用“Bypass for network”选项。 
workbox-webpack-plugin
插件经过了大幅重写,在很多情况下,可以在“零配置”下使用模式。如需了解更新后的 API Surface,请参阅文档。
- API 现在公开了两个类:
GenerateSW和InjectManifest。这使得模式之间的切换变得明确,而在 v2 行为中,行为因swSrc的存在而发生变化。 - 默认情况下,系统会预缓存 webpack 编译流水线中的资源,因此不再需要配置 
globPatterns。继续使用globPatterns的唯一原因是,您需要预缓存 webpack build 中未包含的资源。一般来说,迁移到 v3 插件时,您应先移除所有以前的基于glob的配置,并仅在特别需要时重新添加。 
获取帮助
我们预计大多数迁移都非常简单。如果您遇到本指南未涵盖的问题,请在 GitHub 上提交问题告知我们。