【问题标题】:Service worker add files from API call to precacheService Worker 将 API 调用中的文件添加到预缓存
【发布时间】:2019-01-10 01:41:58
【问题描述】:

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

  1. 从异步 API 获取 URL 列表
  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,
}),

【问题讨论】:

    标签: service-worker workbox


    【解决方案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');
    

    【讨论】:

      【解决方案2】:

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

      问题是workbox.precaching.* 上的辅助方法实际上在后台创建了自己的PrecacheController 实例。由于您正在创建自己的PrecacheController 实例并且调用workbox.precaching.precacheAndRoute([...]),因此您最终会得到两个不能一起工作的PrecacheController 实例。

      从您的代码示例看来,您正在创建一个PrecacheController 实例,因为您希望在运行时加载文件列表以进行预缓存。没关系,但如果您要这样做,有几点需要注意:

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

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

      【讨论】:

        猜你喜欢
        • 2016-02-23
        • 2023-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-26
        • 2016-10-28
        • 1970-01-01
        相关资源
        最近更新 更多