]> git.0d.be Git - nanofun.git/blobdiff - service-worker.js
add progressive web app stuff (manifest & service worker)
[nanofun.git] / service-worker.js
diff --git a/service-worker.js b/service-worker.js
new file mode 100644 (file)
index 0000000..4d25f26
--- /dev/null
@@ -0,0 +1,117 @@
+/* global self, caches, fetch, URL, Response */
+'use strict';
+
+var config = {
+  version: 'v1',
+  staticCacheItems: [
+    'index.html',
+    'jquery.min.js',
+    'nanofun.js',
+    'nanofun.css'
+  ]
+};
+
+function cacheName (key, opts) {
+  return `${opts.version}-${key}`;
+}
+
+function addToCache (cacheKey, request, response) {
+  if (response.ok) {
+    var copy = response.clone();
+    caches.open(cacheKey).then( cache => {
+      cache.put(request, copy);
+    });
+  }
+  return response;
+}
+
+function fetchFromCache (event) {
+  return caches.match(event.request).then(response => {
+    if (!response) {
+      throw Error(`${event.request.url} not found in cache`);
+    }
+    return response;
+  });
+}
+
+function offlineResponse (resourceType, opts) {
+  return undefined;
+}
+
+self.addEventListener('install', event => {
+  function onInstall (event, opts) {
+    var cacheKey = cacheName('static', opts);
+    return caches.open(cacheKey)
+      .then(cache => cache.addAll(opts.staticCacheItems));
+  }
+
+  event.waitUntil(
+    onInstall(event, config).then( () => self.skipWaiting() )
+  );
+});
+
+self.addEventListener('activate', event => {
+  function onActivate (event, opts) {
+    return caches.keys()
+      .then(cacheKeys => {
+        var oldCacheKeys = cacheKeys.filter(key => key.indexOf(opts.version) !== 0);
+        var deletePromises = oldCacheKeys.map(oldKey => caches.delete(oldKey));
+        return Promise.all(deletePromises);
+      });
+  }
+
+  event.waitUntil(
+    onActivate(event, config)
+      .then( () => self.clients.claim() )
+  );
+});
+
+self.addEventListener('fetch', event => {
+
+  function shouldHandleFetch (event, opts) {
+    var request            = event.request;
+    var url                = new URL(request.url);
+    var criteria           = {
+      isGETRequest      : request.method === 'GET',
+      isFromMyOrigin    : url.origin === self.location.origin
+    };
+    var failingCriteria    = Object.keys(criteria)
+      .filter(criteriaKey => !criteria[criteriaKey]);
+    return !failingCriteria.length;
+  }
+
+  function onFetch (event, opts) {
+    var request = event.request;
+    var acceptHeader = request.headers.get('Accept');
+    var resourceType = 'static';
+    var cacheKey;
+
+    if (acceptHeader.indexOf('text/html') !== -1) {
+      resourceType = 'content';
+    } else if (acceptHeader.indexOf('image') !== -1) {
+      resourceType = 'image';
+    }
+
+    cacheKey = cacheName(resourceType, opts);
+
+    if (resourceType === 'content') {
+      event.respondWith(
+        fetch(request)
+          .then(response => addToCache(cacheKey, request, response))
+          .catch(() => fetchFromCache(event))
+          .catch(() => offlineResponse(resourceType, opts))
+      );
+    } else {
+      event.respondWith(
+        fetchFromCache(event)
+          .catch(() => fetch(request))
+            .then(response => addToCache(cacheKey, request, response))
+          .catch(() => offlineResponse(resourceType, opts))
+      );
+    }
+  }
+  if (shouldHandleFetch(event, config)) {
+    onFetch(event, config);
+  }
+
+});