2

I'm creating a pwa using the nuxt/pwa module. I managed to detect a change in the service worker on the install event of the workbox:

plugins/pwa-update.js

export default async (context) => {
  const workbox = await window.$workbox
  if (!workbox) {
    alert("Workbox couldn't be loaded.")
    return
  }

  workbox.addEventListener('installed', (event) => {
    if (!event.isUpdate) {
      alert('The PWA is on the latest version.')
      return
    }
    
    console.log(workbox)

    alert('There is an update for the PWA, reloading...')
    
    window.location.reload()
  })
}

and clear the old cache version with:

#static/custom-sw.js

self.addEventListener('activate', (event) => {
    const LATEST_VERSION = 'v0.998'
    if (caches) {
        caches.keys().then((arr) => {
        arr.forEach((key) => {
            if (key.indexOf('app-precache') < -1) {
            caches
                .delete(key)
                .then(() =>
                console.log(
                    `%c Cleared ${key}`,
                    'background: #333; color: #ff0000'
                )
                )
            } else {
            caches.open(key).then((cache) => {
                cache.match('version').then((res) => {
                if (!res) {
                    cache.put(
                    'version',
                    new Response(LATEST_VERSION, {
                        status: 200,
                        statusText: LATEST_VERSION,
                    })
                    )
                } else if (res.statusText !== LATEST_VERSION) {
                    caches
                    .delete(key)
                    .then(() =>
                        console.log(
                        `%c Cleared Cache ${res.statusText}`,
                        'background: #333; color: #ff0000'
                        )
                    )
                } else {
                    console.log(
                    `%c Great you have the latest version ${LATEST_VERSION}`,
                    'background: #333; color: #00ff00'
                    )
                }
                })
            })
            }
        })
        })
    }
})

Here is my nuxt.config.js

export default {
  // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
  ssr: false,
  ...,
  plugins: [
    ...,
    { src: '~/plugins/pwa-update.js', ssr: false },
  ],
  pwa: {
    meta: {
      title: 'App',
      description: 'App',
      author: '...',
    },
    icon: {
      source: 'icon2.png',
      fileName: 'icon2.png',
      iconSrc: 'icon2.png',
    },
    manifest: {
      name: 'App',
      short_name: 'App',
      lang: 'it',
      theme_color: '#0ca86c',
      background_color: '#0ca86c',
      useWebmanifestExtension: false,
      display: 'standalone',
      start_url: '/',
    },
    workbox: {
      enabled: true,
      cacheNames: {
        prefix: 'app',
      },
      importScripts: [
        'custom-sw.js',
      ],
    },
  },
}

BUT, I dont really understand how the update detection works. For example, if I deploy a new server side version with the updated version in the custom-sw.js file, I still need to manually reload the page to detect the change and show the new version alert. I was not expecting that the user has to manually reload the page. Is it possible to trigger the pwa-update event listener without reloading the page?
For example, with a push notification?

kissu
  • 40,416
  • 14
  • 65
  • 133
Green
  • 376
  • 5
  • 15
  • To my knowledge, this is not doable if you don't already have some kind of local watcher (on user's devices within your SW). Also, people usually close their tabs, browser or just reboot their hardware. I doubt somebody will keep their page open for 4 months doing nothing. – kissu Dec 27 '21 at 15:58
  • @kissu, thank you for your reply. You are actually right, for the moment this behavior is enough. Maybe I can achieve this in the future with push notifications. – Green Dec 28 '21 at 16:36

1 Answers1

2

Here's how I implemented a procedure to check for new updates. Please keep in mind that I haven't tested it with a installable app, just with the website version

  1. Create a static file version.txt that contains a random string. That file is regenerated upon build. This means, any new npm run generate will change the content of that file
  2. I have a component in all layouts that is in charge of fetching the version.txt file every few minutes. When it is fetched, I compare the contents with some item that I keep in localStorage, say _app_version. If the item is not present in localStorage, it means the app was loaded for the first time. If it exists and it's different than the new one it means the server has new code and I force the user to reload the app using a blocking/unclosable confirmation modal.
Florin Miu
  • 46
  • 2
  • Thank you for your reply. As kissu mentioned, the solution works fine for now, at the next app opening, the new service worker will take over and the alert will be shown. I will go for something similar to your solution in the future. – Green Jan 20 '22 at 12:36
  • I tried to implement now your solution. Im able to get my layouts to check for the version on the server (/version.txt), it is not cached so I always get the most recent version. However, when I do a window.reload(true), the runtime cache is not deleted. I suppose I still have to use a plugin to hook on the new service worker lifecycle, so that I can delete the caches. If I can ask, how do you clear the runtime and precache in workbox? thank you – Green Mar 04 '22 at 12:22
  • @Green I am not using workbox. Maybe this will help https://stackoverflow.com/questions/54376355/clear-workbox-cache-of-all-content – Florin Miu Mar 06 '22 at 14:28
  • Hi Florin, thank you again for the answer, in the end I was able to make it work by writing a custom-sw that is injected into the sw by nuxt/pwa. This custom-sw contains the version and checks if it has to delete old caches (names have the version) by using the code you can find on the web. To make sure that the user reloads the page, I created a static/version.txt which is checked periodically as you suggested. Maybe a littlebit cumbersome, but it works. – Green Mar 09 '22 at 10:38