PWA Offline Caching Revisited

Hi,

I have come to the conclusion that the default fetch addEventListener in ServiceWorker.js in the project folder only works for the project html file and does not fetch any other files.

Replacing it with the one shown below, from https://developers.google.com/web/fundamentals/primers/service-workers updates the offline cache.

Thanks,

Ken

self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}

    return fetch(event.request).then(
      function(response) {
        // Check if we received a valid response
        if(!response || response.status !== 200 || response.type !== 'basic') {
          return response;
        }

        // IMPORTANT: Clone the response. A response is a stream
        // and because we want the browser to consume the response
        // as well as the cache consuming the response, we need
        // to clone it so we have two streams.
        var responseToCache = response.clone();

        caches.open(CACHE_NAME)
          .then(function(cache) {
            cache.put(event.request, responseToCache);
          });

        return response;
      }
    );
  })
);

});

Hello Ken,
my JS knowledge is somewhat limited. Would you mind to elaborate a little further as to where to put these 2 code snippets?
Does this patch heal the problem that the installed PWA app won't correctly refresh on the client side in case a change was made on the server side?
Many Thanks,
Walter

Hi Walter,

Just replace the whole of the fetch event listener function in the ServiceWorker.js that is in your project source folder.

Please note that you will need two of these files, one for debug and one for release. Thanks to the forethought of TMS these can be configured separately in the TMS Web options.

The debug version should have the original fetch function but I've found that should also remove the $(FileList) from the CACHED_URLS.

I hope this helps as it now works perfectly for me.

Regards,

Ken

Hi Ken,

many thanks for your explanations!

So now I understand that I need to have 2 versions of ServiceWorker.js in my project folder, say, ServiceWorkerDebug.js and ServiceWorkerRelease.js. ServiceWorkerDebug.js should look like this:

var CACHE_NAME = "$(ProjectName)";
var CACHED_URLS = [
  "$(ProjectHTML)"
  ];

self.addEventListener('install', function(event) {
                event.waitUntil(
                                caches.open(CACHE_NAME).then(function(cache) {
                                return cache.addAll(CACHED_URLS);
                })
                                );
});


self.addEventListener('fetch',function(event) {
   event.respondWith(
     fetch(event.request).catch(function() {
                   return caches.match(event.request).then(function(response) {
       if (response) {
                                   return response;
       } else if (event.request.headers.get("accept").includes("text/html")) {
                                   return caches.match("$(ProjectHTML)");
                   }
                   });
   })
                   );
});

which is the original version except for the $(FileList) removed from CACHED_URLS.

ServiceWorkerRelease.js should look like this:

var CACHE_NAME = "$(ProjectName)";
var CACHED_URLS = [
  "$(ProjectHTML)",
  $(FileList)
  ];

self.addEventListener('install', function(event) {
                event.waitUntil(
                                caches.open(CACHE_NAME).then(function(cache) {
                                return cache.addAll(CACHED_URLS);
                })
                                );
});

self.addEventListener('fetch', function(event) {
                event.respondWith(
                                caches.match(event.request)
                                                .then(function(response) {
                                                                // Cache hit - return response
                                                                if (response) {
                                                                                return response;
                                                                }
                                                }
                )
}

This version should have the $(FFileList) remain in CACHED_URLS, right?

Now, what still puzzles me is the second code snippet that you provided. The one that starts with

return fetch(event.request).then(

What am I supposed to do with this code?

Sorry for probably asking noob questions...

Kind regards

Walter

Hi Walter,

In the release version just replace:

self.addEventListener('fetch',function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return caches.match(event.request).then(function(response) {
if (response) {
return response;
} else if (event.request.headers.get("accept").includes("text/html")) {
return caches.match("$(ProjectHTML)");
}
});
})
);
});

with:

self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}

    return fetch(event.request).then(
      function(response) {
        // Check if we received a valid response
        if(!response || response.status !== 200 || response.type !== 'basic') {
          return response;
        }

        // IMPORTANT: Clone the response. A response is a stream
        // and because we want the browser to consume the response
        // as well as the cache consuming the response, we need
        // to clone it so we have two streams.
        var responseToCache = response.clone();

        caches.open(CACHE_NAME)
          .then(function(cache) {
            cache.put(event.request, responseToCache);
          });

        return response;
      }
    );
  })
);

});

I should add that this has not been confirmed by TMS but works fine for me.

Regards,

Ken

I should add that now the caching is being done for all files you also need to have your .htaccess file( or equivalent) set up correctly.

Be aware that when you update the files on your site, the next time your wpa app is run by a user they will still be running the previous version, but it will be downloading the files in the background. When they close and reopen it again it will then be on the new version.

Thank you very much Ken! I will give this a try.
Walter