2

I am trying to have a service worker respond to fetch events depending on the type of request made. For static resources I use cache:

// TODO: make cache update when item found
const _fetchOrCache = (cache, request) => {
  return cache.match(request).then(cacheResponse => {

    // found in cache
    if (cacheResponse) {
      return cacheResponse
    }

    // has to add to cache
    return fetch(request)
      .then(fetchResponse => {
        // needs cloning since a response works only once
        cache.put(request, fetchResponse.clone())
        return fetchResponse
      });
  }).catch(e => { console.error(e) })
}

for api responses I have already wired up IndexedDB with Jake Archibald's IndexedDB Promised to return content like this:

const fetchAllItems = () => {
    return self.idbPromise
        .then(conn => conn.transaction(self.itemDB, 'readonly'))
        .then(tx => tx.objectStore(self.itemDB))
        .then(store => store.getAll())
        .then(storeContents => JSON.stringify(storeContents));
}

when I call everything in the service worker the cache part works, but the indexedDB fails miserably throwing an error that it cannot get at the api url:

self.addEventListener("fetch", event => {

    // analyzes request url and constructs a resource object
    const resource = getResourceInfo(event.request.url);

    // handle all cachable requests
    if (resource.type == "other") {
        event.respondWith(
            caches.open(self.cache)
                .then(cache => _fetchOrCache(cache, event.request))
        );
    }

    // handle api requests
    if (resource.type == "api") {
        event.respondWith(
            new Response(fetchAllItems());
        );    
    }
});

My questions would be as follows:
1.) Is there any point in separating storing fetch requests like this?
2.) How do I make the indexedDB part work?

Lukas
  • 409
  • 1
  • 5
  • 15

1 Answers1

1

good catch on using Jake Archibalds promise based idb. There are many ways to install his idb. The quickest - download the idb.js file somewhere(this is the library). Then import it on the first line in the service worker likeso:

    importScripts('./js/idb.js');

    .....

    //SW installation event
    self.addEventListener('install', function (event) {
        console.log("[ServiceWorker] Installed");
    });


    //SW Actication event (where we create the idb)
    self.addEventListener('activate', function(event) {
        console.log("[ServiceWorker] Activating");
        createIndexedDB();
    });


   .....

   //Intercept fetch events and save data in IDB

   .....


    //IndexedDB
    function createIndexedDB() {
      self.indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB;

      if (!(self.indexedDB)) { console.console.log('IDB not supported'); return null;}

      return idb.open('mydb', 1, function(upgradeDb) {
        if (!upgradeDb.objectStoreNames.contains('items')) {
          upgradeDb.createObjectStore('items', {keyPath: 'id'});
        }
      });
    }

Judging by the code you pasted above to retrieve IDB data, it is unclear to me what exactly is idbPromise... Are you sure you declared this variable?

You should have something like this

importScripts('./js/idb.js');

//...
//createIdb and store
//...

var idbPromise = idb.open('mydb');

//and after that you have your code like idbPromise.then().then()...

So you create the IDB and the tables during the SW activation. After that you intercept the fetch events and start using the indexeddb like in the tutorials you've seen.

Good luck

Roman Gherta
  • 821
  • 2
  • 15
  • 27
  • Thank you for your answer, I should have included that the code itself is already imported and wired up. It is the fetch part I am having problems with. Will update the question. – Lukas Jul 25 '18 at 15:03