Search code examples
google-chromecachingbrowser-cacheservice-worker

How to tell Service Worker which files to cache


What I’m doing

I’m building a Service Worker component. I want it to have:

  • A single worker.js file containing the Service Worker implementation.
  • I want to be able to tell the worker which files to cache, as well as the name of the cache.
    • Why? I want to require this module in several projects and I don’t want any of them to modify the worker file. The worker should be able to receive a list of paths to cache.

What I’ve tried

  • I tried passing a configuration object to the register method but it didn’t work. The worker didn't receive the object.
  • Taking advantage of the postMessage API which is available on the worker I did this:
    1. In the registration of the worker, I’ve sent a message to the worker containing an object with the routes to cache.
    2. Inside the worker, I’ve subscribed the worker to this message and used the paths to create the cache.

See it for yourself

Registration of the worker in the main thread

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/worker.js').then(function(reg) {
        navigator.serviceWorker.controller.postMessage({
            'hello': 'world',
            cacheName: 'v1',
            urlsToCache: [
                "/index.html"
            ]
        });
    }, function(err) {
        console.log('ಠ_ಠ   Nope.', err);
    });
}

The worker file

'use strict';

var cacheName,
    urlsToCache;

importScripts('/node_modules/serviceworker-cache-polyfill/index.js');

self.addEventListener('message', function (evt) {
    cacheName = evt.data.cacheName;
    urlsToCache = evt.data.urlsToCache;
});

self.addEventListener('install', function(event) {
    setTimeout(function(){
        event.waitUntil(
            caches.open(cacheName)
            .then(function(cache) {
                console.log('Opened cache:', cache);
                return cache.addAll(urlsToCache);
            })
        );
    }, 2000);

});

What is wrong with this?

I had to delay the opening of the cache by using a setTimeout, which is wrong, ugly and unreliable.

What are you trying to achieve, man? ಠ_ಠ

I want to find a way to tell the worker to wait until the message containing the paths to cache arrives.

Link to my repo

Thanks in advance.


Solution

  • I've sent you a Pull Request: https://github.com/cristianelias/serviceworker_component/pull/1. Basically what I did is use the cache object from the page itself as follow:

    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/worker.js').then(function(reg) {
          caches.open('pages').then(function(pages){
             return pages.add('test.html'); 
          }).then(function(){
             console.log('cached!'); 
          });
        }, function(err) {
          console.log('ಠ_ಠ   Nope.', err);
      });
    }
    

    And instructed the SW to only perform a cache match:

    'use strict';
    
    self.addEventListener('fetch', function(event) {
        event.respondWith(
            caches.match(event.request).then(function(match){
                return match || fetch(event.request); 
            })
        );
    });
    

    It works as expected on Chrome 45, I don't know on older versions since moving the cache object to the page is quite a new thing.