本指南重点介绍 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'
的别名。此令牌已失效,开发者应改为直接使用'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: []};
};
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 的开发者。如需了解更新后的 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
在 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(...);
skipWaiting
和clientsClaim
不再是传递给WorkboxSW
构造函数的选项。取而代之的是workbox.clientsClaim()
和workbox.skipWaiting()
方法。- v2 构造函数中之前支持的
handleFetch
选项在 v3 中不再受支持。如果开发者需要使用类似功能来测试其 Service Worker,而无需调用任何提取处理程序,则可以使用 Chrome 开发者工具中的 Bypass for network 选项。
workbox-webpack-plugin
插件经过大幅重写,在许多情况下,可在“零配置”模式下使用。如需了解更新后的 API Surface,请参阅文档。
- API 现在公开了两个类:
GenerateSW
和InjectManifest
。这会使模式之间的切换变得显式,而不是行为基于swSrc
的存在而更改的 v2 行为。 - 默认情况下,系统会预缓存 webpack 编译流水线中的资源,不再需要配置
globPatterns
。继续使用globPatterns
的唯一原因是,您需要预缓存 webpack 构建中未包含的资源。一般来说,迁移到 v3 插件时,您首先应移除之前所有基于glob
的配置,只有在特别需要时才重新添加。
获取帮助
我们预计大多数迁移都是非常简单的。如果您遇到本指南未涵盖的问题,请在 GitHub 上提交问题告知我们。