Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating PWA created with cra-template-pwa

I created a PWA with create-react-app using the cra-template-pwa template but I am having troubles updating the app on change.

Now content is detected correctly and the message is displayed in the console:

New content is available and will be used when all tabs for this page are closed. See https://cra.link/PWA

The problem is, that even after refreshing the page via window.location.reload(true);, the content is not updated. In the browser I actually have to do a hard re-load with Shift + F5 to get the new content to display.

This lead me to believe that I might need to delete the Caches, but doing so results in a ERR_FAILED in the browser.

So what is the correct way to reload my PWA after an update?

This is the relevant function handling the updates:

function registerValidSW(swUrl, config) {
  navigator.serviceWorker.
    register(swUrl).
    then((registration) => {

      registration.update();

      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        if (installingWorker === null) {
          return;
        }
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              console.log('New content is available and will be used when all ' +
                'tabs for this page are closed. See https://cra.link/PWA.',);

              toast.info('Update available! Click to update app.', {
                toastId: 'appUpdateAvailable',
                onClose: () => {
                  window.caches.keys().then((keys) => {
                    for(let i = 0; i < keys.length; i += 1) {
                      caches.delete(keys[i]);
                    }
                    window.location.reload(true);
                  });

                },
                autoClose: false
              });

              // Execute callback
              if (config && config.onUpdate) {
                config.onUpdate(registration);
              }
            } else {
              console.log('Content is cached for offline use.');

              // Execute callback
              if (config && config.onSuccess) {
                config.onSuccess(registration);
              }
            }
          }
        };
      };
    }).
    catch((error) => {
      console.error(
        'Error during service worker registration:',
        error
      );
    });
}
like image 383
stylesuxx Avatar asked Oct 18 '25 02:10

stylesuxx


1 Answers

The trick is to skip waiting for the new service worker.

I adjusted the service worker registration like so:

function registerValidSW(swUrl, config) {
  navigator.serviceWorker.
    register(swUrl).
    then((registration) => {

      registration.update();
      setInterval(() => {
        // Check for updates every 5 minutes
        registration.update();
      }, 1000 * 60 * 5);

      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        if (installingWorker === null) {
          return;
        }
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              /*
               * At this point, the updated precached content has been fetched,
               * but the previous service worker will still serve the older
               * content until all client tabs are closed.
               */
              console.log('New content is available and will be used when all ' +
                'tabs for this page are closed. See https://cra.link/PWA.',);

              registration.waiting.postMessage({ type: 'SKIP_WAITING' });
              toast.info('Update available! To update, refresh this tab.', {
                toastId: 'appUpdateAvailable',
                autoClose: false
              });

              // Execute callback
              if (config && config.onUpdate) {
                config.onUpdate(registration);
              }
            } else {
              /*
               * At this point, everything has been precached.
               * It's the perfect time to display a
               * "Content is cached for offline use." message.
               */
              console.log('Content is cached for offline use.');

              // Execute callback
              if (config && config.onSuccess) {
                config.onSuccess(registration);
              }
            }
          }
        };
      };
    }).
    catch((error) => {
      console.error(
        'Error during service worker registration:',
        error
      );
    });
}

Which will notify the user that a new update is available and he has to refresh his browser. After a simple re-load, the new version is then loaded. No need to clear the caches manually.

like image 131
stylesuxx Avatar answered Oct 19 '25 16:10

stylesuxx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!