【问题标题】:How to check for installed web app (PWA) updates when using precache method使用预缓存方法时如何检查已安装的 Web 应用 (PWA) 更新
【发布时间】:2021-02-23 09:29:23
【问题描述】:

我有一个渐进式 Web 应用程序,其中服务工作者的配置如下所示。我遵循预缓存方法。每个文件将首先被缓存,请求将从缓存中提供。如果本地缓存中没有匹配项,则通过网络提供请求。如果一切都失败了,则会显示一个离线/错误页面。一切正常。但我坚持更新 index.html 文件。

const pb_cache = "cv1";
const assets = [
    "./manifest.json",
    "./index.html",
    "./offline.html",
]

self.addEventListener("install", installEvent => {
  installEvent.waitUntil(
    caches.open(pb_cache)
    .then((cache) => {
      return cache.addAll(assets)
      .then(() => {
        return self.skipWaiting(); //To forces the waiting service worker to become the active service worker
      })
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        return response;
      }
      return fetch(event.request).then(function(response) {
        if (response.status === 404) {
          return caches.match('/offline.html');
        }
        return response
      });
    }).catch(function() {
      return caches.match('/offline.html');
    })
  );
});

场景 我已将网络应用程序安装到我的安卓手机上。一切都被缓存并且工作正常。我需要对 index.html 文件进行更改。所以我在文件中添加了一些调整并更新了网站。但是由于安装在android中的web app服务于本地缓存,所以网站的变化并没有体现出来。所以我需要一种机制来检查更新。我应该检查什么参数或什么东西来更新?我已经阅读了许多与此相关的文档,但我无法掌握其中的内容。

我知道的一件事是,我必须检查服务工作者中某处的更新,并在网络中找到时将其添加到缓存中。我不知道要检查哪个事件或什么条件。

【问题讨论】:

    标签: progressive-web-apps service-worker service-worker-events


    【解决方案1】:

    执行此操作的“手动”方法是包含类似

    // VERSION: 1
    

    在您的 Service Worker 文件的顶部,并记住在您对 install 期间缓存的资产进行任何更改时更改该编号。更新的版本号将导致自动service worker update check 指示有新内容,这反过来又会触发更新后的服务工作者文件中的install 处理程序再次触发。此时您的所有预缓存资产将再次添加到缓存中。

    在 cmets 中进行了一些澄清后,我认为在 install 处理程序中使用 cache.addAll() 可能会出现问题,因为您无法控制 Cache-Control 标头,而 cache.addAll() 将转到访问网络之前的 HTTP 缓存。这是一个替代的install 处理程序,它可以通过传入具有适当cache 属性的Request 对象来解决此问题,而不是传入URL 字符串:

    self.addEventListener("install", installEvent => {
      const cacheBypassRequests = assets.map(
        (url) => new Request(url, {cache: 'reload'});
    
      installEvent.waitUntil(
        caches.open(pb_cache)
        .then((cache) => {
          return cache.addAll(cacheBypassRequests)
          .then(() => {
            return self.skipWaiting();
          })
        })
      );
    });
    

    这显然容易出错,因为当您对其中一项资产进行小幅调整时,您可能会忘记调整该值。

    一种更稳健的方法是在您的 Web 应用程序的构建过程中添加一个步骤,该步骤将在您每次重新部署时更新您的 Service Worker 文件的版本号。

    一种更适合生产的方法是使用旨在解决此特定用例的工具,例如 workbox-precaching 以及节点、webpack 或 CLI 构建接口。这将负责自动生成您要预缓存的每个资产的哈希,每当其中一个发生更改时触发新安装,并且仅重新下载更新的资产。

    【讨论】:

    • 好的。如果我使用容易出错的第一种方法,那么在更新当前缓存之前清除以前的缓存是否可以解决缓存问题?
    • cache.addAll() 将用从网络检索到的任何内容覆盖以前的条目,因此您不必先明确清除任何内容。但是您确实需要记住更新手动版本字符串,并且您需要确保您的 HTTP Cache-Control 标头不会导致您检索先前缓存的响应,即确保您的缓存标头允许您直接进入到网络。
    • 我不是 HTTP 缓存控制标头方面的专家。我在 github 中托管此代码。那你能解释一下吗?
    • 还有哪个更好?每次更改时添加// VERSION: 1或更新缓存名称?
    • 不,它不会绕过 HTTP 缓存。不过,我可以调整我的原始答案以显示cache.addAll() 的替代方案,它将绕过 HTTP 缓存。
    【解决方案2】:

    此实现最简单的解决方案是在您更改index.html 时更新pb_cache 值,这将导致更新服务工作线程并重新缓存index.html。但是,旧的缓存版本不会被删除。

    这是一个使用Workbox 的解决方案,它将预先缓存urls 中指示的文件,然后当对其中一个文件发出请求时,它将使用stale, while revalidate 策略。用户最初可能会看到旧版本,但在下一次重新加载时,他们将获得最新版本。对于任何其他请求(不在urls 中的请求,它将使用network only 策略。最后,如果无法从网络获取页面,setCatchHandler 将返回离线页面。

    importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.1.0/workbox-sw.js');
    
    // URLs to cache and keep up to date
    const urls = [
      '/index.html',
      '/manifest.json',
      '/script.js',
      '/style.css',
      '/offline.html',
    ];
    
    // Turn on logging for development, change to false for production
    workbox.setConfig({
      debug: true
    });
    
    const {clientsClaim} = workbox.core;
    const {NetworkOnly} = workbox.strategies;
    const {StaleWhileRevalidate} = workbox.strategies;
    const {warmStrategyCache} = workbox.recipes;
    const {registerRoute} = workbox.routing;
    const {setDefaultHandler} = workbox.routing;
    const {setCatchHandler} = workbox.routing;
    
    self.skipWaiting();
    clientsClaim();
    
    // Normalize cache key URLs to:
    // - drop query parameters
    // - for URLs ending in '/', append 'index.html'
    async function cacheKeyWillBeUsed({request}) {
      const url = new URL(request.url);
      if (url.pathname.endsWith('/')) {
        return url.origin + url.pathname + 'index.html';
      }
      return url.origin + url.pathname;
    }
    
    // Initialize a stale while revalidate strategy.
    // See https://developers.google.com/web/tools/workbox/modules/workbox-strategies#stale-while-revalidate
    const strategy = new StaleWhileRevalidate({
      plugins:[
        {cacheKeyWillBeUsed},
      ],
    });
    
    // Ensure that an initial set of URLs are cached,
    // so that the PWA works offline immediately.
    warmStrategyCache({urls, strategy});
    
    // Use the Stale While Revalidate strategy for URLs in `urls`
    registerRoute(
      ({url}) => {
        let pathname = url.pathname;
        // Normalize paths, for URLs ending in '/', append 'index.html'
        if (pathname.endsWith('/')) {
          pathname += 'index.html';
        }
        return urls.includes(pathname);
      }, strategy
    );
    
    // Use only the network for all other requests
    setDefaultHandler(new NetworkOnly());
    
    // This "catch" handler is triggered when any of the other routes fail to
    // generate a response. This is a simplified version of the Comprehensive Fallback
    // https://developers.google.com/web/tools/workbox/guides/advanced-recipes#comprehensive_fallbacks
    setCatchHandler(({event}) => {
      if (event.request.destination === 'document') {
        return caches.match('/offline.html');
      }
    });
    

    整个解决方案结合了来自 Workbox 的 Advanced Recipes 部分的许多配方。

    【讨论】:

    • 在这里更改缓存名称看起来很合适。我稍后会考虑工作箱选项。覆盖以前的缓存还是删除并添加为新缓存更好?
    • 删除并添加一个新的缓存稍微好一点。
    • 好的。正如其他答案中的其他人所提到的,每次进行更改时将 // VERSION: 1 添加到工作文件或更新缓存名称?哪个更好?
    • 感谢您的帮助。非常感谢。我对如何制作这个有一个大概的想法:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多