17

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?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
StampyCode
  • 7,218
  • 3
  • 28
  • 44

2 Answers2

41

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
});
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
mixel
  • 25,177
  • 13
  • 126
  • 165
38

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.

StampyCode
  • 7,218
  • 3
  • 28
  • 44
  • 1
    That is not required. But it looks like you are 'scoping' your PWA to that folder. So you needed to scope it. The reason you were getting that error is there was no service worker fetch event handler in place for that scope. This post talks about that requirement: https://love2dev.com/blog/is-your-progressive-web-app-may-not-prompting-the-customer-to-add-to-home-screen/ – Chris Love Oct 06 '17 at 17:13
  • 1
    It's just not a documented requirement (not even on your site) that when scoping an app you need to specify the scope in the calling script, adding the scope to the manifest doesn't work, the call to the serviceWorker in the website code defaults to root scope, and ignores the manifest. This might be a bug in the ServiceWorker implementation to be quite frank. If _all_ of my website files are stored in the relative directory, there should be no requirement for absolutely scoping the app, it just hinders deployment to a secondary location. – StampyCode Oct 07 '17 at 07:13
  • 2
    @ChrisLove in fact, I just found that you can set the scope to `.` and it works. So although the parameter is still required in my client script, it now can at least be ignorant of the absolute path. – StampyCode Oct 07 '17 at 07:22
  • The Service Worker and the Web Manifest are not interdependent. You can have either without the other. The scope in the manifest is for navigational purposes. "Defines the navigation scope of this web application's application context. This basically restricts what web pages can be viewed while the manifest is applied. If the user navigates the application outside the scope, it returns to being a normal web page." https://developer.mozilla.org/en-US/docs/Web/Manifest – Chris Love Oct 07 '17 at 17:33
  • 1
    For some reason ( https://stampy.me/pwgen/ ) its not working offline now. It gives an error that website cannot be reached. I am on a macOS using Chrome 67. – Hassan Jul 07 '18 at 21:19
  • 1
    https://stampy.me/pwgen/ isn't working offline on Windows10 + Chrome 73. It shows the typical error "website cannot be reached". Any clue? – LuBre Mar 20 '19 at 15:37
  • Was also checking offline status now and got the "offline error" since my PWA also does not want to work offline – deanwilliammills Jun 25 '19 at 11:44
  • I blindly copied your answer to my project and it has broken my cache. When you set scope in manifest.json, don't set it in service worker registration. – Konrad Aug 19 '19 at 21:12