Motivated by the sudden appearance of the "Add to home screen" prompt, I spent the last couple of hours to tune my Service Worker / caching behaviour:

- I can now exclude parts of my site from the service worker. This was an important feature for me, since the WordPress backend didn't sit too well with stubborn cached items.

- I established a number of caches for different items:
-- a "static" cache that has the base css and the page that gets displayed when the network is offline.
-- a "content" cache, that stores up to 25 URLs a visitor has, well, visited, while being online.
-- an "image" cache, that stores up to 45 image files, and finally
-- an "asset" cache for up to 35 files (everything that is not HTML and not an image).

The limits are rather random, but I think each cache has an build-in maximum of 50 entries (?), so to see if it works, I choosed numbers smaller than that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
'use strict';
(function() {
 
    // Update 'version' if you need to refresh the cache
    const version = '0.1.1';
 
    const staticCache = 'wbr_static';
    const contentCache = 'wbr_content';
    const imgCache = 'wbr_images';
    const assetCache = 'wbr_assets';
    const staticCacheName = version + '_' + staticCache;
    const contentCacheName = version + '_' + contentCache;
    const imgCacheName = version + '_' + imgCache;
    const assetCacheName = version + '_' + assetCache;
 
    // urls that should not be controlled/cached
    const neverCache = [
    	'piwik',
    	'/jaguar/',
  	'/blog/wp-admin/'
    ];
 
    // helper for checking the neverCache array
    var testPos = function(cur,idx,arr){
        // 'this' will be triggered by the 'thisVar' param in array.some(callback,thisVar),
	// i.e. neverCache.some(testPos,request.url)
	if( this.indexOf(cur) !== -1 ){
	    return true;
	}
	return false;
    }
 
    // Store core files in a cache (including a page to display when offline)
    var updateStaticCache = function() {
        return caches.open( staticCacheName )
            .then(function (cache) {
                return cache.addAll([
                    '/blog/wp-content/themes/wbr-theme/style.css',
                    '/blog/wp-content/uploads/2016/04/image-6-530x398.png',
                    '/',
                    '/offline.html'
                ]);
            });
    };
 
    // Put an item in a specified cache
    var stashInCache = function(cacheName, request, response) {
        caches.open(cacheName)
            .then(function (cache) {
                cache.put(request, response);
            });
    };
 
    // Limit the number of items in a specified cache.
    var trimCache = function(cacheName, maxItems) {
        caches.open(cacheName)
            .then(function (cache) {
                cache.keys()
                    .then(function (keys) {
                        if (keys.length > maxItems) {
                            cache.delete(keys[0])
                                .then(trimCache(cacheName, maxItems));
                        }
                    });
            });
    };
 
    // Remove caches whose name is no longer valid
    var clearOldCaches = function() {
    	return caches.keys()
            .then(function (keys) {
                return Promise.all(keys
                    .filter(function (key) {
                      return key.indexOf(version) !== 0;
                    })
                    .map(function (key) {
                      return caches.delete(key);
                    })
                );
            })
    }
 
    self.addEventListener('install', function (event) {
        event.waitUntil(updateStaticCache()
            .then(function () {
                return self.skipWaiting();
            })
        );
    });
 
    self.addEventListener('activate', function (event) {
        event.waitUntil(clearOldCaches()
            .then(function () {
                return self.clients.claim();
            })
        );
    });
 
    self.addEventListener('message', function(event) {
    	if (event.data.command == 'trimCaches') {
    		trimCache(contentCacheName, 25);
    		trimCache(imgCacheName, 45);
    		trimCache(assetCacheName, 35);
    	}
    });
 
    self.addEventListener('activate', function (event) {
        event.waitUntil(
            caches.keys()
                .then(function (keys) {
                    // Remove caches whose name is no longer valid
                    return Promise.all(keys
                        .filter(function (key) {
                          //console.log(key);
                          //console.log(key.indexOf(version) !== 0);
                          return key.indexOf(version) !== 0;
                        })
                        .map(function (key) {
                          return caches.delete(key);
                        })
                    );
                })
        );
    });
 
    self.addEventListener('fetch', function (event) {
 
        var request = event.request;
 
        // if is request for cms admin, do nothing.
        if( neverCache.some(testPos,request.url)){
        	return
        }
 
        // Always fetch non-GET requests from the network
        if (request.method !== 'GET') {
            event.respondWith(
                fetch(request)
                    .catch(function () {
                        return caches.match('/offline.html');
                    })
            );
            return;
        }
 
        // For HTML requests, try the network first, fall back to the cache, finally the offline page
        if (request.headers.get('Accept').indexOf('text/html') !== -1) {
            // Fix for Chrome bug: https://code.google.com/p/chromium/issues/detail?id=573937
            if (request.mode != 'navigate') {
                request = new Request(request.url, {
                    method: 'GET',
                    headers: request.headers,
                    mode: request.mode,
                    credentials: request.credentials,
                    redirect: request.redirect
                });
            }
            event.respondWith(
                fetch(request)
                    .then(function (response) {
                        // Stash a copy of this page in the cache
                        var copy = response.clone();
                        stashInCache(contentCacheName, request, copy);
                        return response;
                    })
                    .catch(function () {
                        return caches.match(request)
                            .then(function (response) {
                                return response || caches.match('/offline.html');
                            })
                    })
            );
            return;
        }
 
        // For non-HTML requests,
        // - look in the cache first,
        // - fall back to the network, cache it,
        // - else show offline img if is image request
        event.respondWith(
            caches.match(request)
                .then(function (response) {
                    return response || fetch(request)
                    	// update asset | image cache
                    	.then(function (response) {
                        	// Stash a copy of this page in the cache.
                        	var copy = response.clone();
                        	var myCache = assetCacheName;
                        	if (request.headers.get('Accept').indexOf('image') !== -1) {
                        		myCache = imgCacheName;
                        	}
                        	stashInCache(myCache, request, copy);
                        	return response;
                    	})
                        .catch(function () {
                            // If the request is for an image, show an offline placeholder
                            if (request.headers.get('Accept').indexOf('image') !== -1) {
                                return new Response('Offlineoffline', { headers: { 'Content-Type': 'image/svg+xml' }});
                            }
                        });
                })
        );
    });
})();

I'm quite pleased with myself because the script still works after all these changes, and I think I'm beginning to grasp how this hot new stuff is supposed to work :-)

Thanks Jeremy @adactio for the "blogServiceworker" gist, and Steffen @webgefrickel for the idea for the "neverCache" array.