服务工作者将文件从API调用添加到预缓存

时间:2018-08-02 10:13:21

标签: service-worker workbox

启用我的应用离线运行。在安装过程中,服务人员应:

  1. 从异步API获取网址列表
  2. 重新设置响应格式
  3. 将响应中的所有URL添加到预缓存中

对于此任务,我将Google Workbox与Webpack结合使用。

问题:虽然服务工作者成功地缓存了所有Webpack资产(这告诉我工作箱基本上已经完成了应做的事情),但它没有等待异步API调用来缓存其他远程资产。它们只会被忽略,并且不会在网络中缓存或获取。

这是我的服务人员代码:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.1.0/workbox-sw.js');

workbox.skipWaiting();
workbox.clientsClaim();

self.addEventListener('install', (event) => {
  const precacheController = new workbox.precaching.PrecacheController();
  const preInstallUrl = 'https://www.myapiurl/Assets';
  event.waitUntil(fetch(preInstallUrl)
    .then(response => response.json()
      .then((Assets) => {
        Object.keys(Assets.data.Assets).forEach((key) => {
          precacheController.addToCacheList([Assets.data.Assets[key]]);
        });
      })));
});
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

workbox.routing.registerRoute(/^.*\.(jpg|JPG|gif|GIF|png|PNG|eot|woff(2)?|ttf|svg)$/, workbox.strategies.cacheFirst({ cacheName: 'image-cache', plugins: [new workbox.cacheableResponse.Plugin({ statuses: [0, 200] }), new workbox.expiration.Plugin({ maxEntries: 600 })] }), 'GET');

这是我为工作箱配置的webpack:

new InjectManifest({
  swDest: 'sw.js',
  swSrc: './src/sw.js',
  globPatterns: ['dist/*.{js,png,html,css,gif,GIF,PNG,JPG,jpeg,woff,woff2,ttf,svg,eot}'],
  maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
}),

2 个答案:

答案 0 :(得分:1)

我意识到自己的错误。我希望这对其他人也有帮助。问题是我没有手动调用precacheController.install()。尽管此功能将自动执行,但它不会等待异步插入的其他预缓存文件。这就是在所有预缓存发生后需要调用该函数的原因。这是工作代码:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.1.0/workbox-sw.js');

workbox.skipWaiting();
workbox.clientsClaim();

const precacheController = new workbox.precaching.PrecacheController();

// Hook into install event
self.addEventListener('install', (event) => {
  // Get API URL passed as query parameter to service worker
  const preInstallUrl = new URL(location).searchParams.get('preInstallUrl');

  // Fetch precaching URLs and attach them to the cache list
  const assetsLoaded = fetch(preInstallUrl)
    .then(response => response.json())
    .then((values) => {
      Object.keys(values.data.Assets).forEach((key) => {
        precacheController.addToCacheList([values.data.Assets[key]]);
      });
    })
    .then(() => {
      // After all assets are added install them
      precacheController.install();
    });
  event.waitUntil(assetsLoaded);
});

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

workbox.routing.registerRoute(/^.*\.(jpg|JPG|gif|GIF|png|PNG|eot|woff(2)?|ttf|svg)$/, workbox.strategies.cacheFirst({ cacheName: 'image-cache', plugins: [new workbox.cacheableResponse.Plugin({ statuses: [0, 200] }), new workbox.expiration.Plugin({ maxEntries: 600 })] }), 'GET');

答案 1 :(得分:1)

看起来您正在创建自己的PrecacheController实例,并且还使用了precacheAndRoute(),实际上并没有打算将它们一起使用(在文档中没有进行很好的解释,只是提到了在this one place中)。

问题是workbox.precaching.*上的辅助方法实际上在后台创建了自己的PrecacheController实例。由于您正在创建自己的PrecacheController实例,并且调用workbox.precaching.precacheAndRoute([...]),因此最终将导致两个PrecacheController实例无法协同工作。< / p>

从您的代码示例中,您似乎正在创建一个PrecacheController实例,因为您希望在运行时将文件列表加载到预缓存中。很好,但是如果您要这样做,则需要注意以下几点:

  • 您的软件可能不会更新 通常,当您调用navigator.serviceWorker.register()并且浏览器检测到服务工作者文件已更改时,会触发服务工作者更新。这意味着,如果您更改了/Assets返回的内容,但您的服务人员文件的内容没有更改,则您的服务人员将不会更新。这就是为什么大多数人在服务工作者中硬编码其预缓存列表的原因(因为对这些文件的任何更改都会触发新的服务工作者的安装)。

  • 您将必须手动添加自己的路线 我之前提到过workbox.precaching.precacheAndRoute([...])在后​​台创建自己的PrecacheController实例。它还adds its own fetch listener manually来响应请求。这意味着,如果您不使用precacheAndRoute(),则必须创建自己的路由器并定义自己的路由。以下是有关如何创建路线的文档:https://developers.google.com/web/tools/workbox/modules/workbox-routing