Service Worker 确定客户端数量

Service Worker determine number of clients

我们有一个支持 PWA 的 SaaS 应用程序,我们正在使用 Workbox 进行繁重的工作。到目前为止,我们一直在遵循向用户显示更新可用横幅的尝试和信任的方法,提示他们更新他们的网络应用程序。

查看使用数据(通过 Sentry.io)我们注意到大多数用户似乎只是忽略了更新横幅并继续使用他们正在使用的版本。

所以我们正在考虑尝试一些不同的东西。这是为了在他们更改网络应用程序中的路由时自动执行更新(当我们知道有可用更新时)。

测试表明它确实有效。但是有一个 side-effect,那就是如果他们在多个选项卡中打开了网络应用程序,那么所有选项卡都会更新。如果用户在后台的其中一个选项卡中打开了一个 un-saved 表单,这对他们来说可能会有问题 - 他们可能会丢失他们的工作。

这发生在这段代码中:

// app shell page, created lifecycle hook
document.addEventListener('swUpdated', this.SetPwaRegistration, { once: true })
navigator.serviceWorker.addEventListener('controllerchange', () => {
  if (this.refreshing) {
    return
  }
  this.refreshing = true
  window.location.reload()
})

// app shell page, method in methods collection
SetPwaRegistration (event) {
  // call mutation to pass the registration object to Vuex
  this.PWA_REGISTRATION_SET({ pwaRegistration: event.detail })
}

// main.js
router.afterEach((to, from) => {
  // retrieve the registration object from Vuex
  const pwaRegistration = app.$store.getters.pwaRegistration
  if (pwaRegistration) {
      pwaRegistration.waiting.postMessage('skipWaiting')
  }
})

以上代码来自我们的Vue.js应用程序code-base,this.refreshing在[=14=中默认设置为false ] 属性 collection.

我想知道是否可以确定 Service Worker 是否只有一个客户端受其控制(即网络应用程序仅在 1 个浏览器选项卡中打开),如果是这种情况, auto-update 可以在没有潜在问题的情况下发生。如果有多个客户端,那么我们将照常显示更新横幅。


作为对此的简短更新,我遇到了与此类似的代码示例:

self.clients.matchAll().then(clients => {
  const clientCount = clients.length
  // store count of client in Vuex
})

这看起来像是一个选项(即计算有多少客户端,将其存储在 Vuex 存储中),我只是不确定应该在哪里使用它。

如果你想完全从 service worker 中安排重新加载,你可以通过使用 WindowClient 接口以编程方式导航到当前 URL 的任何内容来有效地做到这一点,这大致是相当于重新加载。

要记住的两件事是 navigate() 仅适用于 WindowClients(而不是 Workers)并且您只能在 service worker 控制时调用它WindowClient.

综上所述,这里有一些值得尝试的东西:

// This can be run, e.g., in a `message` handler in your SW:
self.clients.matchAll({
  // These options are actually the defaults, but just
  // to be explicit:
  includeUncontrolled: false,
  type: 'window',
}).then((clients) => {
  if (clients.length === 1) {
    clients[0].navigate(clients[0].url);
  }
})