从 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' 的别名。此令牌已失效,开发者应改为直接使用 'staleWhileRevalidate'
  • 多个 runtimeCaching.options 属性名称已更新,并进行了额外的参数验证,如果使用了无效配置,将导致构建失败。如需查看当前支持的选项列表,请参阅 runtimeCaching文档

工作框后台同步

  • maxRetentionTime 配置参数现在解释为分钟数,而不是毫秒数。
  • 现在有一个表示队列名称的必需字符串,在构建 Plugin 或 standalone 类时,必须将其作为第一个参数传入。(以前,它是作为选项的属性传入的。)如需了解更新后的 API Surface,请参阅文档

workbox-broadcast-cache-update

  • 现在需要一个表示频道名称的字符串,在构建 Plugin 或 standalone 类时,必须将它作为第一个参数传入。

例如,在 v2 中,您应按如下方式初始化 Plugin 类:

new workbox.broadcastCacheUpdate.BroadcastCacheUpdatePlugin({
  channelName: 'cache-updates',
  headersToCheck: ['etag'],
});

v3 中的等效用法如下:

new workbox.broadcastUpdate.Plugin('cache-updates', {headersToCheck: ['etag']});

如需了解更新后的 API Surface,请参阅文档

工作区构建

  • 默认情况下,现在使用选项 follow: true(将位于符号链接后面)和 strict: true(对“异常”错误的容忍度较低)执行 glob 模式匹配。您可以通过在 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 manifestArray;,而应使用 return {manifest: manifestArray};)。这样一来,您的插件便可以添加可选的 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 的开发者。如需了解更新后的 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

在 v3 中,将使用从 workbox-cli-config.js 读取的配置运行“注入清单”构建流程:

$ 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 样式”通配符的支持已被移除。这会大大缩减 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,而无需调用任何提取处理程序,则可以使用 Chrome 开发者工具中的 Bypass for network 选项。
Chrome 开发者工具中的“Bypass for Network”选项。

workbox-webpack-plugin

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

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

获取帮助

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