Search code examples
javascriptservice-workerworkbox

workbox precacheAndRoute does not handle window.fetch or XMLHttpRequest


When using workbox (5.1.3) and setting up the service-worker.js like

precacheAndRoute([
  {url: '/version.txt', revision: 'v1' },
]);

I can navigate in browser to localhost://version.txt and see inside chrome console that this content is fetched via caching from workbox.

Message in console shows:

workbox Precaching is responding to: /version.txt

But when trying to fetch the resource inside my javascript app via:

  window
    .fetch('/version.txt')
    .then((response) => {
      if (response.status >= 200 && response.status < 300) {
        return response.text();
      } else {
        throw Error('no version');
      }
    })
    .then((data) => {
      console.log('content: ' + data);
    })
    .catch((error) => {
      console.log(error);
    });
}

the fetch command will try to read this content directly from network and skipping workbox Precaching. Also when simulating offline, I get an error for fetch instead the cached response.

Getting crazy ;-)


Solution

  • After digging further into this issue - I found the problem (at least on my site)

    Full working example:

    /index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>My New Project!</title>
    </head>
    <body>
      <h1>Example Service Worker</h1>
      <p>A simple Test</>
      <!-- Scripts -->
      <script src="index.js"></script>
    </body>
    </html>
    

    /index.js

    let registration;
    
    var initServiceWorker = () => {
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker
          .register('./sw.js')
          .then((reg) => registration = reg)
          .catch((error) => console.log('Registration failed with ' + error));
      }
    }
    
    var fetchTest = () => {
      console.log('VERSION FETCH Test looking for: /version.txt');
      window
        .fetch('/version.txt', { method: 'GET'})
        .then((response) => {
          if (response.status >= 200 && response.status < 300) {
            return response.text();
          } else {
            throw Error('no version.txt file');
          }
        })
        .then((data) => {
          console.log('AVILABLE VERSION FETCH: ' + String(data).trim());
        })
        .catch((error) => {
          console.log(error);
        });
    }
    
    var xmlhttpTest = () => {
      console.log('VERSION XHR Test looking for: /version.txt');
    
      var xhr = new XMLHttpRequest();
      xhr.open("GET", '/version.txt', true);
    
      xhr.onload = function (e) {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            console.log('AVILABLE VERSION XHR: ' + xhr.responseText);
          }
        }
      }
    
      // initialize request
      xhr.send(null);
    }
    
    console.log("JavaScript is amazing!");
    
    initServiceWorker();
    
    setTimeout(() => fetchTest(), 5000);
    
    setTimeout(() => xmlhttpTest(), 10000);
    
    setTimeout(() => { console.log('Registration update ...'); registration.update()}, 20000);
    
    setTimeout(() => fetchTest(), 30000);
    
    setTimeout(() => xmlhttpTest(), 35000);
    

    /sw.js

    // Sample service worker
    const SW_VERSION = 'a2';
    
    self.addEventListener('install', (event) => {
      console.log('SW INSTALL: ' + SW_VERSION);
      skipWaiting();
    });
    
    self.addEventListener('activate', (event) => {
      console.log('SW ACTIVATE: ' + SW_VERSION);
      skipWaiting();
    });
    
    self.addEventListener("fetch", function(event) {
      console.log('WORKER (' + SW_VERSION + '): fetch event in progress ... ' + event.request.url);
      if (event.request.method !== 'GET') {
        console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
        return;
      }
    });
    

    /version.txt

    v1.0.0
    

    You may have a look into your console to see that also while using FETCH or XMLHTTREQUEST the fetch event from service worker will drop a message.


    And now about (my) issue:

    If placing the javascript (/index.js) with fetch and xmlHttprequest in the same place (scope) as service-worker (/sw.js) everything works as expected

    BUT

    if leaving the javascript in a subfolder like (/js/index.js) THIS WON'T TOUCH THE FETCH LISTENER from service-worker (/sw.js) ANYMORE even if /js should be in scope???

    Strange but happy to get that now ;-)