From e30593f84947ae2e5188cee071746634661fe0d4 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Sun, 6 Dec 2020 05:38:36 +0100 Subject: [PATCH 1/4] dev12060537 - ServiceWorker basic boilerplate Added a boilerplate for a offline-first sw. Need to add support for non-standard same-origin assets --- public/assets/js/script.js | 3 ++ public/sw.js | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/public/assets/js/script.js b/public/assets/js/script.js index e69de29..91142fd 100644 --- a/public/assets/js/script.js +++ b/public/assets/js/script.js @@ -0,0 +1,3 @@ +if(navigator.serviceWorker) { + navigator.serviceWorker.register("sw.js"); +} \ No newline at end of file diff --git a/public/sw.js b/public/sw.js index e69de29..e909c92 100644 --- a/public/sw.js +++ b/public/sw.js @@ -0,0 +1,65 @@ +const activeCaches = [ + "content-v1" +]; + +const root = "/victorwesterlund.com/public/"; + +self.addEventListener("install", event => { + event.waitUntil( + caches.open("content-v1").then(cache => cache.addAll([ + root, + root + "assets/css/style.css", + root + "assets/img/favicon.png", + root + "assets/js/script.js", + root + "assets/fonts/RobotoMono-Bold.woff2", + root + "assets/fonts/RobotoMono-Regular.woff2" + ])) + ) +}); + +self.addEventListener("activate", event => { + event.waitUntil( + // Delete inactive caches + caches.keys().then(cacheNames => { + return Promise.all( + cacheNames.map(cacheName => { + if(!activeCaches.includes(cacheName)) { + return caches.delete(cacheName); + } + }) + ) + }) + ) +}); + +/* ---- */ + +function handleRequest(event) { + const networkFetch = fetch(event.request); + + event.waitUntil( + networkFetch.then(response => { + const responseClone = response.clone(); + caches.open("downloaded").then(cache => cache.put(event.request, responseClone)); + }) + ); + + return caches.match(event.request).then(response => response || networkFetch); +} + +self.addEventListener("fetch", event => { + const url = new URL(event.request.url); + + console.log(url); + if(url.origin != location.origin) { + event.respondWith(fetch(url.href)); + } + + // if(url.origin == location.origin && url.pathname == root) { + // event.respondWith(caches.match("index.html")); + // return; + // } + + event.respondWith(caches.match(url.pathname) || handleRequest(event)); +}); +// Victor Westerlund From e8dd97a2917d9bde722c1441cd9ca7c4d6340578 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Mon, 7 Dec 2020 07:27:40 +0100 Subject: [PATCH 2/4] Added pattern.gif "redirect" with SW Added placeholder 'pattern.php' script. SW: Added uniform version control. 'handleRequest()' is now 'fetchContent()' and automatically saves response to 'bucket' Cahce Storage (removed between SW versions) Added uniform same-origin check with 'const origin'. Fixed issue where "cache lookup -> fetch fallback" wouldn't actually load content from cache. --- public/assets/img/pattern.php | 8 +++++++ public/sw.js | 41 +++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 public/assets/img/pattern.php diff --git a/public/assets/img/pattern.php b/public/assets/img/pattern.php new file mode 100644 index 0000000..93cfa1f --- /dev/null +++ b/public/assets/img/pattern.php @@ -0,0 +1,8 @@ + { event.waitUntil( - caches.open("content-v1").then(cache => cache.addAll([ + caches.open(`content-${version}`).then(cache => cache.addAll([ root, root + "assets/css/style.css", root + "assets/img/favicon.png", root + "assets/js/script.js", + root + "assets/img/pattern.gif", root + "assets/fonts/RobotoMono-Bold.woff2", root + "assets/fonts/RobotoMono-Regular.woff2" ])) @@ -32,15 +34,14 @@ self.addEventListener("activate", event => { ) }); -/* ---- */ - -function handleRequest(event) { +// Fetch and save content to bucket +function fetchContent(event) { const networkFetch = fetch(event.request); event.waitUntil( networkFetch.then(response => { const responseClone = response.clone(); - caches.open("downloaded").then(cache => cache.put(event.request, responseClone)); + caches.open("bucket").then(cache => cache.put(event.request, responseClone)); }) ); @@ -50,16 +51,24 @@ function handleRequest(event) { self.addEventListener("fetch", event => { const url = new URL(event.request.url); - console.log(url); - if(url.origin != location.origin) { + const origin = (url.origin == location.origin) ? true : false; // Is same-origin + + // Fetch cross-origin content + if(!origin) { event.respondWith(fetch(url.href)); + return; } - // if(url.origin == location.origin && url.pathname == root) { - // event.respondWith(caches.match("index.html")); - // return; - // } + // Get pattern.gif from generator. Fall back to cache on failure + if(origin && url.pathname.endsWith("pattern.gif")) { + const pattern = new Request(`${location.origin}/${root}/assets/img/pattern.php`); + event.respondWith(fetch(pattern) || caches.match(event.request).then(response => response)); + return; + } - event.respondWith(caches.match(url.pathname) || handleRequest(event)); + // Respond with content for cache or fetch and save + event.respondWith( + caches.match(event.request).then(response => response || fetchContent(event)) + ); }); // Victor Westerlund From 9a2e937f1bfecf6e519461d52a2b9e9d03df1d04 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Wed, 9 Dec 2020 08:08:54 +0100 Subject: [PATCH 3/4] Update sw.js --- public/sw.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/sw.js b/public/sw.js index 0d1cd46..f61d9ae 100644 --- a/public/sw.js +++ b/public/sw.js @@ -50,7 +50,6 @@ function fetchContent(event) { self.addEventListener("fetch", event => { const url = new URL(event.request.url); - const origin = (url.origin == location.origin) ? true : false; // Is same-origin // Fetch cross-origin content @@ -59,10 +58,10 @@ self.addEventListener("fetch", event => { return; } - // Get pattern.gif from generator. Fall back to cache on failure + // Get pattern.gif from generator. Fallback to cache on failure if(origin && url.pathname.endsWith("pattern.gif")) { - const pattern = new Request(`${location.origin}/${root}/assets/img/pattern.php`); - event.respondWith(fetch(pattern) || caches.match(event.request).then(response => response)); + const pattern = new Request(`${location.origin}/${root}assets/img/pattern.php`); + event.respondWith(fetch(pattern) || caches.match(url.pathname).then(response => response)); return; } From a2f002dcadd4777049aa7718fbfbb9944c6f0e55 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Mon, 14 Dec 2020 08:01:37 +0100 Subject: [PATCH 4/4] Added Service Worker for offline caching Removed Google Analytics script. --- public/index.html | 10 ---------- public/sw.js | 12 +++++++++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/public/index.html b/public/index.html index 7cccf4c..f3931c9 100644 --- a/public/index.html +++ b/public/index.html @@ -1,13 +1,6 @@ - - - @@ -17,9 +10,6 @@ Victor Westerlund - - -
diff --git a/public/sw.js b/public/sw.js index f61d9ae..a484376 100644 --- a/public/sw.js +++ b/public/sw.js @@ -9,6 +9,7 @@ self.addEventListener("install", event => { event.waitUntil( caches.open(`content-${version}`).then(cache => cache.addAll([ root, + root + "offline.txt", root + "assets/css/style.css", root + "assets/img/favicon.png", root + "assets/js/script.js", @@ -35,7 +36,7 @@ self.addEventListener("activate", event => { }); // Fetch and save content to bucket -function fetchContent(event) { +async function fetchContent(event) { const networkFetch = fetch(event.request); event.waitUntil( @@ -45,7 +46,8 @@ function fetchContent(event) { }) ); - return caches.match(event.request).then(response => response || networkFetch); + const response = await caches.match(event.request); + return response || networkFetch; } self.addEventListener("fetch", event => { @@ -61,7 +63,11 @@ self.addEventListener("fetch", event => { // Get pattern.gif from generator. Fallback to cache on failure if(origin && url.pathname.endsWith("pattern.gif")) { const pattern = new Request(`${location.origin}/${root}assets/img/pattern.php`); - event.respondWith(fetch(pattern) || caches.match(url.pathname).then(response => response)); + event.respondWith( + fetch(pattern).catch(() => { + return caches.match(event.request); + }) + ); return; }