diff --git a/gulpfile.js b/gulpfile.js index 2148989..15f4c9d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -23,7 +23,7 @@ var outDir = 'out/'; var paths = { html: ['index.html'], images: ['images/*.png'], - extras: ['manifest.json', 'favicon.ico', 'single-page-offline-service-worker.js'], + extras: ['manifest.json', 'favicon.ico', 'simple-offline-service-worker.js'], }; gulp.task('clean', function() { diff --git a/index.js b/index.js index 63fa137..15b61b8 100644 --- a/index.js +++ b/index.js @@ -107,10 +107,9 @@ window.addEventListener('DOMContentLoaded', function() { if (rightConversionTypeFromDOM !== rightConversionType) onRightTypeChanged(); - // We queue a task to setup the offline cache so it doesn't affect the critical path. - setTimeout(function() { - setupOfflineCache(); - }, 500); + // Bootup our service worker for offline support. + if ('serviceWorker' in navigator) + navigator.serviceWorker.register('simple-offline-service-worker.js'); }); function updateConversion() { @@ -287,10 +286,3 @@ function imageType(file) { } return ''; } - -function setupOfflineCache() { - if (!('serviceWorker' in navigator)) - return; - // Disabled for testing. - // navigator.serviceWorker.register('single-page-offline-service-worker.js'); -} \ No newline at end of file diff --git a/simple-offline-service-worker.js b/simple-offline-service-worker.js new file mode 100644 index 0000000..08970d3 --- /dev/null +++ b/simple-offline-service-worker.js @@ -0,0 +1,45 @@ +'use strict'; +// Simple offline service worker. +// +// On the main page include: +// if ('serviceWorker' in navigator) +// navigator.serviceWorker.register('simple-offline-service-worker.js'); +// +// This cache always requests from the network to keep the cache fresh. There is a tradeoff here +// because we'll wait ages for a slow network despite having a cached response ready to go. + +var version = 'v1.0.2'; + +// FIXME: Is it possible to serve from ./ and also have an offline app using manifest.json without +// making two requests? +var offlineFiles = [ './', './index.html' ]; + +self.addEventListener('install', function(event) { + // Cache our list of files. + event.waitUntil(caches.open(version).then(function(cache) {cache.addAll(offlineFiles); })); +}); + +self.addEventListener('activate', function(event) { + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener('fetch', function(event) { + event.respondWith( + fetch(event.request).then(function(networkReponse) { + // Check if this request is already in our cache. We only want to cache previously + // cached items to prevent the cache from getting polluted. + caches.open(version).then(function(cache) { + cache.match(event.request).then(function(previouslyCachedResponse) { + if (!previouslyCachedResponse) + return; + // Clone the response since we're also returning it below. + cache.put(event.request, networkReponse.clone()); + }); + }); + return networkReponse; + }).catch(function(networkIssue) { + // Return from the cache if available, or explode which will 404. + return caches.match(event.request); + }) + ); +}); diff --git a/single-page-offline-service-worker.js b/single-page-offline-service-worker.js deleted file mode 100644 index 618d908..0000000 --- a/single-page-offline-service-worker.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; -// Very simple single page offline service worker. -// -// On the main page include: -// if (!('serviceWorker' in navigator)) -// return; -// navigator.serviceWorker.register('single-page-offline-service-worker.js'); - -// Version key for cache in case entries need to be removed in the future. -var version = 'v1.0.0'; -var offlineFiles = [ 'index.html' ]; - -self.addEventListener('install', function(event) { - function cacheAllFiles(cache) { - return cache.addAll(offlineFiles); - } - - event.waitUntil(caches.open(version).then(cacheAllFiles)); -}); - -// Delete stale cache entries on activation. -self.addEventListener('activate', function(event) { - function removeStaleKeys(keys) { - function keyNotEqual(key) { - return key !== version; - } - function deleteKey(key) { - return caches.delete(key); - } - return Promise.all(keys.filter(keyNotEqual).map(deleteKey)); - } - - event.waitUntil(caches.keys().then(removeStaleKeys)); -}); - -self.addEventListener('fetch', function(event) { - if (event.request.method !== 'GET') - return; - - // Eventually fresh approach, see: - // https://ponyfoo.com/articles/progressive-networking-serviceworker - function eventuallyFreshResponse(cached) { - function fetchedFromNetwork(response) { - var cacheCopy = response.clone(); - caches.open(version).then(function add(cache) { - cache.put(event.request, cacheCopy); - }); - return response; - } - - var networked = fetch(event.request).then(fetchedFromNetwork); - return cached || networked; - } - - event.respondWith(caches.match(event.request).then(eventuallyFreshResponse)); -});