使用 Workbox 预缓存

预缓存是您需要在 Service Worker 中最常执行的操作之一,无论您选择哪一种 Workbox 构建工具,Workbox 都为完成这项重要任务提供了极大的灵活性。在本指南中,您将了解如何使用 generateSWinjectManifest 预缓存资源,以及其中哪些方法可能最适合您的项目。

使用 generateSW 预缓存

generateSW 是在 Workbox 中预缓存资源的最简单方法。关于 generateSW 的重点在于,您不是编写自己的 Service Worker,而是要求 Workbox 为您生成一个 Service Worker。不过,您可以通过各种配置选项来影响其行为。

默认情况下,generateSW 会执行不同的操作,具体取决于您使用的构建工具。使用 workbox-webpack-plugin 时,您不必指定任何配置选项。默认情况下,该插件会预缓存 Webpack 依赖关系图中包含的所有内容,并将名为 service-worker.js 的 Service Worker 写入 output.path 指定的目录中。

另一方面,如果您使用 workbox-buildworkbox-cli,则默认情况下,系统只会预缓存从本地文件系统读取的 HTML、CSS 和 JavaScript 资源。在配置方面,您必须在 generateSW 配置中指定 swDestglobDirectory 选项,才能进行预缓存。您可能也需要配置影响 Service Worker 行为的其他选项,因此请仔细阅读相关文档。

使用 injectManifest 预缓存

使用 injectManifest 不像使用 generateSW 那么简单,但牺牲了易用性,换取了更大的灵活性。generateSW 会为您处理整个 Service Worker 生成过程,而 injectManifest 将您编写的 Service Worker 作为其来源,并注入要预缓存的网址列表,同时让 Service Worker 的其余部分保持原样。

使用 injectManifest 时,您需要负责连接预缓存逻辑。当 injectManifest 检查输入 Service Worker 时,它会查找一个特殊的 self.__WB_MANIFEST 变量并将其替换为预缓存清单。如果此变量不存在,injectManifest 会抛出错误。

可以使用其他配置选项调整预缓存清单中的条目列表。

并列比较

点击以下各个标签页可比较 generateSWinjectManifest 方法的用法:

由于 generateSW 会生成 Service Worker,因此您只需指定配置。以下是使用 workbox-build 的示例:

// build-sw.js
import {generateSW} from 'workbox-build';

generateSW({
  swDest: './dist/sw.js',
  globDirectory: './dist',
  globPatterns: [
    '**/*.js',
    '**/*.css',
    '**/*.svg'
  ]
});

然后,可以使用 Node 在命令行中构建 Service Worker:

node build-sw.js

由于 injectManifest 需要源 Service Worker,因此一个最低限度的示例需要源 Service Worker 文件。如果只需要预缓存,该输入 Service Worker 可能如下所示:

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute(self.__WB_MANIFEST);

请注意 self.__WB_MANIFEST 字符串。这是 Workbox 用预缓存清单替换的占位符。以下是此用例的有效配置:

// build-sw.js
import {injectManifest} from 'workbox-build';

injectManifest({
  swSrc: './src/sw.js',
  swDest: './dist/sw.js',
  globDirectory: './dist',
  globPatterns: [
    '**/*.js',
    '**/*.css',
    '**/*.svg'
  ]
});

如果您有复杂的要求(例如高级路由、自定义缓存策略或 generateSW 提供的选项未涵盖的其他内容),则建议使用 injectManifest

总结

与必须自行管理预缓存相比,Workbox 中的预缓存要简单得多,尤其是在对捆绑器编译的版本化资源而言。但是,预缓存并不是您在 Service Worker 中需要执行的唯一操作。在此过程中,您将学习其他技术,例如运行时缓存。