• HTML
  • Service Worker
  • PWA
  • JavaScript

PWA: Reload Page on Application Update

With this article I will go over a minimal setup for a Progressive Web Application to automatically reload the page when it picks up changes to it backing service worker.

Why?

I have a Web Assembly application that loads a lot of libraries through the service worker, and it includes an integrity check to these files. This integrity check is done against new files and can fail, because of how the file integrity map is tied to the currently active service worker. The below example will go over flipping to the new service worker using the lifecycle hooks, allowing the new worker to take over the integrity checks.

Source Code Example

This example can be done in two files, the index.html and the service-worker.js, we are just going to hook into the lifecycle events of the service workers. We are going to hook into the updatefound and statechange of the service worker for checking when the service worker becomes active. We will also hook into the controllerchange event to be notified when the service worker is replaced with a new service worker. Using these hooks we are able to know when the service worker is updated and not just the first time it was activated for the site.

// site.js (load this in your index.html)
(function () {
    // We are going to track an updated flag and an activated flag.
    // When both of these are flagged true the service worker was updated and activated.
    let updated = false;
    let activated = false;
    navigator.serviceWorker.register('service-worker.js').then(regitration => {
        regitration.addEventListener("updatefound", () => {
            const worker = regitration.installing;
            worker.addEventListener('statechange', () => {
                console.log({ state: worker.state });
                if (worker.state === "activated") {
                    // Here is when the activated state was triggered from the lifecycle of the service worker.
                    // This will trigger on the first install and any updates.
                    activated = true;
                    checkUpdate();
                }
            });
        });
    });
    navigator.serviceWorker.addEventListener('controllerchange', () => {
        // This will be triggered when the service worker is replaced with a new one.
        // We do not just reload the page right away, we want to make sure we are fully activated using the checkUpdate function.
        console.log({ state: "updated" });
        updated = true;
        checkUpdate();
    });

    function checkUpdate() {
        if (activated && updated) {
            console.log("Application was updated refreshing the page...");
            window.location.reload();
        }
    }
})();
// service-worker.js (register this as a service worker)
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', () => { });

async function onInstall(event) {
    console.info('Service worker: Install');
    // Here we are telling the service worker to activate right away when an update is pickedup.
    // In our main JavaScript this will trigger 'controllerchange', which we can use to trigger an page reload.
    self.skipWaiting();
}

async function onActivate(event) {
    console.info('Service worker: Activate');
}

Cody's logo image, it is an abstract of a black hole with a white Event Horizon.

Cody Merritt Anhorn

A Engineer with a passion for Platform Architecture and Tool Development.