How do I install both a service worker and a manifest with a single Javascript tag? How do I install both a service worker and a manifest with a single Javascript tag? google-chrome google-chrome

How do I install both a service worker and a manifest with a single Javascript tag?


Yes you can reduce the steps to getting them to host a service worker file on their origin and include a single line of Javascript in their page.

You can do it by using the Javascript they include to:

  1. Register a service worker
  2. Inject a link to a non-existent manifest into the head
  3. Intercept the request to that manifestwith your service worker and respond with your custom manifest

Your Javascript should look something like this:

navigator.serviceWorker.register('sw.js').then(function(registration) {    console.log('ServiceWorker registration successful with scope: ', registration.scope);    var head = document.head;    var noManifest = true;    // Walk through the head to check if a manifest already exists    for (var i = 0; i < head.childNodes.length; i++) {        if (head.childNodes[i].rel === 'manifest') {            noManifest = false;            break;        }    }    // If there is no manifest already, add one.    if (noManifest) {        var manifest = document.createElement('link');        manifest.rel = 'manifest';        manifest.href = 'manifest.json';        document.head.appendChild(manifest);    }});

Note how I've avoided adding a manifest tag if one already exists.

Your service worker should look something like:

self.addEventListener('fetch', function(e) {    if (e.request.context === 'manifest') {        e.respondWith(new Promise(function(resolve, reject) {            fetch(e.request).then(function(response) {                if (response.ok) {                    // We found a real manifest, so we should just add our custom field                    response.json().then(function(json) {                        json.custom_field = 'Hello world';                        var blob = new Blob([JSON.stringify(json)], { type: 'application/json' });                        console.log('Appended a custom field to the pre-existing manifest');                        resolve(new Response(blob));                    });                } else {                    // There was no manifest so return ours                    console.log('Injected a custom manifest');                    resolve(new Response('{ "custom_field": "Hello world" }'));                }            });        }));    }});// These pieces cause the service worker to claim the client immediately when it is registered instead of waiting until the next load. This means this approach can work immediately when the user lands on your site.if (typeof self.skipWaiting === 'function') {    console.log('self.skipWaiting() is supported.');    self.addEventListener('install', function(e) {        // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-skipwaiting        e.waitUntil(self.skipWaiting());    });} else {    console.log('self.skipWaiting() is not supported.');}if (self.clients && (typeof self.clients.claim === 'function')) {    console.log('self.clients.claim() is supported.');    self.addEventListener('activate', function(e) {        // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#clients-claim-method        e.waitUntil(self.clients.claim());    });} else {    console.log('self.clients.claim() is not supported.');}

Note how it only intercepts requests for manifests, and checks if one actually exists. If it does, the service worker simply appends our custom fields to it. If the manifest doesn't already exist we return our custom field as the whole manifest.

Update (August 25th 2015): I just read that Request.context has been deprecated so unfortunately you will need to find a new way of discovering whether a request is for a manifest or something else in place of the line if (e.request.context === 'manifest').