Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service Worker: how to update the cache when files changed on the server?

What cache strategies are you using? I read the Offline Cookbook and the simplest strategy to use is to cache static content and the left out the API calls.

This strategy seems something like this:

  1. Check if the request is already in cache
  2. If not add the request, response pair to cache
  3. Return response

How to update the cache if on the server side files has changed? Currently the clients gets always the cached results.

Here is my cache strategy's code:

// You will need this polyfill, at least on Chrome 41 and older.
importScripts("serviceworker-cache-polyfill.js");

var VERSION = 1;

var CACHES = {
    common: "common-cache" + VERSION
};

// an array of file locations we want to cache
var filesToCache = [
    "font-cache.html",
    "script.js",
];

var neededFiles = [
    "index.html"
];

var errorResponse = function() {

    return new Response([
            "<h2>Failed to get file</h2>",
            "<p>Could not retrive response from cache</p>"
        ].join("\n"),
        500
    );
};

var networkFetch = function(request) {

    return fetch(request).then(function(response) {

        caches.open(CACHES["common"]).then(function(cache) {

            return cache.put(request, response);
        });

    }).catch(function() {
        console.error("Network fetch failed");
        return errorResponse();
    });
}

this.addEventListener("install", function(evt) {
    evt.waitUntil(
        caches.open(CACHES["common"]).then(function(cache) {

            // Cache before
            cache.addAll(filesToCache);
            return cache.addAll(neededFiles);
        })
    );
});

this.addEventListener("activate", function(event) {

    var expectedCacheNames = Object.keys(CACHES).map(function(key) {
        return CACHES[key];
    });

    console.log("Activate the worker");

    // Active worker won"t be treated as activated until promise resolves successfully.
    event.waitUntil(
        caches.keys().then(function(cacheNames) {
            return Promise.all(
                cacheNames.map(function(cacheName) {
                    if (expectedCacheNames.indexOf() ===
                        -1) {
                        console.log(
                            "Deleting out of date cache:",
                            cacheName);

                        return caches.delete(cacheName);
                    }
                })
            );
        })
    );
});

self.addEventListener("fetch", function(event) {
    console.log("Handling fetch event for", event.request.url);

    event.respondWith(

        // Opens Cache objects
        caches.open(CACHES["common"]).then(function(cache) {
            return cache.match(event.request).then(function(
                response) {

                if (response) {
                    console.log("Found response in cache", response);

                    return response;
                } else {

                    return networkFetch(event.request);
                }
            }).catch(function(error) {

                // Handles exceptions that arise from match() or fetch().
                console.error(
                    "  Error in fetch handler:",
                    error);

                return errorResponse();
            });
        })
    );
});
like image 939
Risto Novik Avatar asked May 29 '15 07:05

Risto Novik


2 Answers

You may get familiar with great Jeff Posnick's solution - sw-precache.
Strategy used there is:

  1. Gulp is generating Service Worker file with checksums
  2. Service Worker is registered (with his own checksum)
  3. If files were added/updated, the SW file changes
  4. With next visit, SW checks that its checksum differs, so it registers itself once again with updated files

You may automate this flow with backend in any way you want :)

He described it much better in this article

like image 93
Karol Klepacki Avatar answered Sep 19 '22 13:09

Karol Klepacki


This is the code I use to cache. It fetches the resource and caches and serves it.

this.addEventListener("fetch", function(event) {
  event.respondWith(
    fetch(event.request).then(function(response) {
      return caches.open("1").then(function(cache) {
        return cache.put(event.request, response.clone()).then(function() {
          return response
        })
      })
    }).catch(function() {
      return caches.match(event.request)
    })
  )
})
like image 43
Daniel Herr Avatar answered Sep 22 '22 13:09

Daniel Herr