Progressive Web App "does not work offline" error

Viewed 26373

I have written a progressive web app, following all available guides and examples, but for some reason when I click the Add to homescreen button, I keep getting this mysterious error:

Site cannot be installed: does not work offline

The major difference between my PWA and the examples, is that mine is running purely in a non-root path of the domain, so I have had to add extra paths to the configs in various places so the app is restricted to the non-root folder.

The Google Lighthouse site doesn't help much either, giving a very similar message.

Can anyone suggest what this error might be caused by?

2 Answers

Update:

Looks like Google also picked up on the quick hack and the warning has returned.

So since of Chrome93 (AUG-2021) the quick hack, will not work anymore :

self.addEventListener('fetch', function(event) {})

Solution working "for now" (since we never know what requirements Google will add later on)

I've found a nice article which provides with a few solutions, the first one the author provides is Network-Falling-Back-To-Cache strategy:

your service worker will first try to retrieve the resource from your server. Then when it can’t do that — because for example, you’re offline — retrieve it from the cache (if it exists there).

   self.addEventListener('fetch', function(event) {
   event.respondWith(async function() {
      try{
        var res = await fetch(event.request);
        var cache = await caches.open('cache');
        cache.put(event.request.url, res.clone());
        return res;
      }
      catch(error){
        return caches.match(event.request);
       }
     }());
 });

You can find all the information and alternative solutions in the article:

https://javascript.plainenglish.io/your-pwa-is-going-to-break-in-august-2021-34982f329f40

I hope this will help futur visitors.

Original answer:

Also you need to define fetch listener in a service worker file:

this.addEventListener('fetch', function (event) {
    // it can be empty if you just want to get rid of that error
});

So it took me a couple of hours, but I eventually figured out that there is a required scope parameter that you need to specify in the client JavaScript when connecting to the serviceworker, if it's not running on the root (/) path.

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('sw.js?v2', {
        scope: '.' // <--- THIS BIT IS REQUIRED
    }).then(function(registration) {
        // Registration was successful
        console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
        // registration failed :(
        console.log('ServiceWorker registration failed: ', err);
    });
}

You can see the working product here:

I hope my pain can save someone else some time.

Related