9

I'm new to service workers, and I'm using Workbox to precache my app shell and cache my api data.

The precaching of assets is working correctly, with the cache being created and populated.

The runtime caching isn't creating a cache and populating it until I reload the page a second time.

I thought this might be a timing issue, so I set a page reload of the data in the javascript, however this still didn't cache the call.

I'm not doing anything specific to create the cache, app code is:

...
app.getData = function() {
  var requestHeaders = new Headers({
    Accept: "application/json"
  });
  fetch(app.dataUrl, { headers: requestHeaders })
  .then(function(response) {
    return response.json();
  })
  .then(function(json) {
      app.updateCards(json);
  })
  .catch(function(error) {
      console.log('There has been a problem with your fetch operation: ' + error.message);
  });
}
...
if ('serviceWorker' in navigator) {
navigator.serviceWorker
         .register('/my_sw.js')
         .then(function() {
            console.log('Service Worker Registered');
         });
}

app.getData();  # fetch api data

then in the service worker:

 ...
 const workboxSW = new self.WorkboxSW({clientsClaim: true});
 // register data url to cache
 workboxSW.router.registerRoute(
    '/my_api/data',
     workboxSW.strategies.staleWhileRevalidate()
 );
 // pre-cache assets
 workboxSW.precache(fileManifest);

I am using the Chrome Dev tools to check the sw status and the cache created. The network calls to the data URL are as follows:

1st load of page:
enter image description here 2nd load of page:
enter image description here

I'd be grateful for any advice on what I'm doing wrong, or how to debug it.

Thanks in advance
Dan

d_a_n
  • 317
  • 7
  • 16
  • 1
    I don't see anything obviously incorrect about your setup. How are you confirming that the runtime caching (following a reload) isn't working? The Cache Storage viewer in Chrome DevTool's Application panel can sometimes show stale data, and I wonder if that's an issue for you. Also, see https://stackoverflow.com/questions/33590378/status-code200-ok-from-serviceworker-in-chrome-network-devtools/33655173#33655173 for a description of what you should see in the Network panel if the SW intercepts your API request. Finally, is there a URL we could visit and tst things out ourselves? – Jeff Posnick Aug 14 '17 at 18:53
  • @JeffPosnick thanks for your advice. I’m using Clear Storage on the devtool's Application tab to clear everything, then I load the page with an ‘empty cache and hard reload’. The page loads, my api is called and the data appears on the page (see edit above), I right-click on Cache Storage and refresh it - only the one cache of 'workbox-precaching..' appears. I refresh the page with a normal refresh, refresh the Cache Storage, and both the precaching and runtime caches are listed. I've added details of the network calls in the edit above. – d_a_n Aug 15 '17 at 21:57
  • @JeffPosnick I've sent you a link to an example on Twitter. – d_a_n Aug 15 '17 at 23:18
  • 2
    A few things: the service worker doesn't control a page that's loaded via a "hard reload". Using `clientsClaim` means that your service worker will take control of a page as soon as the SW `activate`s, but it does take time for that activation to happen (it has to complete the `install` step first). If your API request is made before the SW takes control, it's not going to be picked up and cached until a subsequent visit. I went to your site and confirm that on the second visit, without hard reloads, the runtime cache is populated. – Jeff Posnick Aug 16 '17 at 15:55
  • @JeffPosnick thanks for looking into it. Ideally I'd like to get the API call cached on the first page load after the SW takes control - any suggestions on how to do this? Can I pre-cache it like my static assets? – d_a_n Aug 16 '17 at 20:27
  • 4
    `window.caches.open('my-cache').then(cache => cache.add(requestUrl));` from your page should do it. When you set up your SW strategy, use `workboxSW.strategies.staleWhileRevalidate({cacheName: 'my-cache'});` so that it uses the same cache. – Jeff Posnick Aug 17 '17 at 00:15

1 Answers1

5

To be safe, you might want to add skipWaitingto the Workbox constructor to ensure the service worker doesn't wait for the page to reload to start caching.

You would also want to wait on serviceWorker.ready in your page before making the API call. This way you know the service worker is active.

These changes together, in your service worker you would have:

 ...
 const workboxSW = new self.WorkboxSW({skipWaiting: true, clientsClaim: true});
 // register data url to cache
 workboxSW.router.registerRoute(
    '/my_api/data',
     workboxSW.strategies.staleWhileRevalidate()
 );
 // pre-cache assets
 workboxSW.precache(fileManifest);

Then in your web page

...
if ('serviceWorker' in navigator) {
    navigator.serviceWorker
      .register('/my_sw.js')
      .then(function() {
        return navigator.serviceWorker.ready;
      })
      .then(function() {
        app.getData();  # fetch api data
      });
}
Matt Gaunt
  • 9,434
  • 3
  • 36
  • 57