使用预缓存方法时如何检查已安装的 Web 应用程序 (PWA) 更新

How to check for installed web app (PWA) updates when using precache method

我有一个 Progressive Web App,其中 service worker 的配置如下所示。我遵循预缓存方法。每个文件都将首先被缓存,请求将从缓存中得到服务。如果本地缓存中没有匹配项,则通过网络提供请求。如果一切都失败,则会显示 offline/error 页面。一切正常。但我一直坚持更新 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');
    })
  );
});

场景 我已将网络应用程序安装到我的 android phone。一切都被缓存并且工作正常。我需要更改 index.html 文件。所以我对文件进行了一些调整并更新了网站。但是由于安装在 android 中的网络应用服务于本地缓存,因此网站的变化没有反映出来。所以我需要一种机制来检查更新。我应该检查什么参数或什么东西来更新?看了很多这方面的资料,还是没能掌握其中的内容。

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

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

的内容
// VERSION: 1

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

在评论中进行一些澄清后,我认为在 install 处理程序中使用 cache.addAll() 可能会有问题,因为您无法控制 Cache-Control headers,而cache.addAll()会先去HTTP缓存再去网络。这是一个替代的 install 处理程序,它通过传入 Request objects 和适当的 cache 属性 而不是传入 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();
      })
    })
  );
});

这显然是 error-prone,因为当您对其中一项资产进行小幅调整时,您可能会忘记增加该值。

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

一种更 production-ready 的方法是使用一种工具来解决这个特定的用例,例如 workbox-precaching 以及节点、webpack 或 CLI 构建接口。这将负责自动生成您要预缓存的每个资产的哈希值,每当其中一个发生变化时触发新安装,并且只有 re-downloading 更新的资产。

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

如果无法从网络获取页面,return 使用 Workbox, it will pre-cache the files indicated in urls, then when a request for one of those files is made, it will use a stale, while revalidate strategy. The user may see an old version initially, but on the next reload, they'll get the latest. For any other requests (that are not in urls, it will use a network only strategy. And finally, 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 部分的许多方法。