Search code examples
service-workerworkbox

Bypass default caching policy if file is managed by service worker


I am using Google's workbox-cli tool in order to precache some of the files on my website. Is it possible to setup the webserver to return the following in the HTTP response header for all files by default:

cache-control: s-maxage=2592000, max-age=86400, must-revalidate, no-transform, public

But, have the webbrowser use the follwing instead only if the file is going to be precached by the service worker:

cache-control: s-maxage=2592000, max-age=0, must-revalidate, no-transform, public

So, I would like the service worker to change max-age=86400 into max-age=0 in the webserver's response header before precaching the file. This makes the service worker fetch files, that have changed according to the revision in sw.js, from the webserver instead of retrieving them from local cache. Any files not managed by the service worker are cached for 86400 seconds by default.

Some background info

Currently, I am using the following bash script to setup my sw.js:

#!/bin/bash
if [ ! -d /tmp/workbox-configuration ]; then
mkdir /tmp/workbox-configuration
fi
cat <<EOF > /tmp/workbox-configuration/workbox-config.js
module.exports = {
  "globDirectory": "harp_output/",
  "globPatterns": [
EOF
( cd harp_output && find assets de en -type f ! -name "map.js" ! -name "map.json" ! -name "markerclusterer.js" ! -name "modal.js" ! -name "modal-map.html" ! -name "service-worker-registration.js" ! -name "sw-registration.js" ! -path "assets/fonts/*" ! -path "assets/img/*-1x.*" ! -path "assets/img/*-2x.*" ! -path "assets/img/*-3x.*" ! -path "assets/img/maps/*" ! -path "assets/img/video/*_1x1.*" ! -path "assets/img/video/*_4x3.*" ! -path "assets/js/workbox-*" ! -path "assets/videos/*" ! -path "de/4*" ! -path "de/5*" ! -path "en/4*" ! -path "en/5*" | sort | sed 's/^/"/' | sed 's/$/"/' | sed -e '$ ! s/$/,/' >> /tmp/workbox-configuration/workbox-config.js )
cat <<EOF >> /tmp/workbox-configuration/workbox-config.js
  ],
  "swDest": "/tmp/workbox-configuration/sw.js"
};
EOF
workbox generateSW /tmp/workbox-configuration/workbox-config.js
sed -i 's#^importScripts(.*);$#importScripts("/assets/js/workbox-sw.js");\nworkbox.setConfig({modulePathPrefix: "/assets/js/"});#' /tmp/workbox-configuration/sw.js
sed -i 's/index.html"/"/' /tmp/workbox-configuration/sw.js
uglifyjs /tmp/workbox-configuration/sw.js -c -m -o harp_output/sw.js

On my Nginx webserver the following HTTP header is delivered by default:

more_set_headers "cache-control: s-maxage=2592000, max-age=0, must-revalidate, no-transform, public";

But, if the requested ressource is not handled by the service worker, the default cache-control setting is overwritten:

location ~ ^/(assets/(data/|fonts/|img/(.*-(1|2|3)x\.|maps/|video/.*_(1x1|4x3)\.)|js/(map|markerclusterer|modal|service-worker-registration|sw-registration)\.js|videos/)|(de|en)/((4|5).*|modal-map\.html)) {
    more_set_headers "cache-control: s-maxage=2592000, max-age=86400, must-revalidate, no-transform, public";
}

Problem with the current approach (see background info)

  1. I have to keep track of the files and update nginx.confcorrespondingly.
  2. max-age=0 is used also for webbrowsers that don't support service-workers. So, they request the ressources from the webservers on each page visit.

1st Update

My desired precaching behaviour can be illustrated with two of the workbox strategies. I want the service worker to show below behaviour as described in scenario 1 and 2, although cache-control: max-age=86400 is delivered in the HTTP header by the webserver for an asset (e.g. default.js).

Scenario 1: revision in sw.js didn't change

The webpage is accessed, the sw.js file is retrieved from the webserver due to max-age=0 and the webbrowser noticed that the revision for default.js didn't change. In this case, default.js is retrieved from the precache cache:

enter image description here

Scenario 2: revision in sw.js did change

The webpage is accessed, the sw.js file is retrieved from the webserver due to max-age=0 and the webbrowser noticed that the revision of default.js changed. In this case, default.js is retrieved from the webserver:

enter image description here

2nd Update

Basically, the desired strategy is similar to the network-first strategy. But, step 2 is only taken if the revision of the file in sw.js has changed.

enter image description here

3rd Update

If I am not mistaken, there is already some work on this:

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(`static-${version}`)
      .then(cache => cache.addAll([
        new Request('/styles.css', { cache: 'no-cache' }),
        new Request('/script.js', { cache: 'no-cache' })
      ]))
  );
});

Solution

  • I used s-max-age instead of s-maxage in the cache-control HTTP header, which lead to some unexpected behaviour with my reverse proxy and workbox service worker. After the fix, the service worker is working as expected.