从 Workbox v2 迁移到 v3

本指南将重点介绍 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 中删除所有日志记录和断言时,调试日志默认处于启用状态。 Workbox v3 提供的调试日志记录示例。
  • 改进了 webpack 插件。workbox-webpack-plugin 与 webpack 构建流程更紧密地集成,因此当您希望预缓存构建流水线中的所有资源时,可实现零配置的用例。

为了实现这些目标,并清理之前的界面中令人感到尴尬或导致反模式的某些方面,需要在 v3 版本中引入一些破坏性更改。

重大变更

构建配置

以下变更会影响我们共用一组通用配置选项的所有构建工具(workbox-buildworkbox-cliworkbox-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: []};
};

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:swinject:manifest 在 v3 中已重命名为 generateSWinjectManifest
  • 在 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(...);
  • skipWaitingclientsClaim 不再是传递给 WorkboxSW 构造函数的选项。而是将它们更改为了 workbox.clientsClaim()workbox.skipWaiting() 方法。
  • 之前在 v2 构造函数中支持的 handleFetch 选项在 v3 中不再受支持。如果开发者需要类似功能来测试其 Service Worker,而不调用任何提取处理程序,则可以使用“Bypass for network”选项。
Chrome 开发者工具中的“绕过网络”选项。

workbox-webpack-plugin

插件经过了大幅重写,在很多情况下,可以在“零配置”下使用模式。如需了解更新后的 API Surface,请参阅文档

  • API 现在公开了两个类:GenerateSWInjectManifest。这使得模式之间的切换变得明确,而在 v2 行为中,行为因 swSrc 的存在而发生变化。
  • 默认情况下,系统会预缓存 webpack 编译流水线中的资源,因此不再需要配置 globPatterns。继续使用 globPatterns 的唯一原因是,您需要预缓存 webpack build 中未包含的资源。一般来说,迁移到 v3 插件时,您应先移除所有以前的基于 glob 的配置,并仅在特别需要时重新添加。

获取帮助

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