Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service Worker not working in Offline mode with node js server

  • I am trying to build a PWA with an offline first policy.
    • The server for the source files is a NodeJS server.
    • I am currently testing this on a localhost node server (not sure it has an impact ?).
    • Service worker + caching seems fine, but in offline mode I only get the Chrome Offline Page.

Let's get into details :

The page which is served (through the http://localhost:8080/place/test url) has some client side JS, in which I register a Service Worker :

client.js

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker
                 .register(rootPath+'/js/service-worker.js')
                 .then(function() { console.log('Service Worker Registered'); });
    }

service-worker.js (based on the Google PWA tutorial)

var cacheName = 'myCacheVersion';
var filesToCache = [
    '../',
    '../place/test',
    '../js/client.js',
    '../js/service-worker.js',
    "../css/style.css"
];


self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== cacheName) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
  );
  return self.clients.claim();
});

self.addEventListener('fetch', function(e) {
  console.log('[ServiceWorker] Fetch', e.request.url);
  e.respondWith(
    caches.match(e.request).then(function(response) {
      return response || fetch(e.request);
    })
  );
});

In the Dev Tools Console, everything seems fine :

  • The SW is registered
  • The cache contains the elements I wanted to cache

But when I check the Offline mode checkbox and refresh my page url : http://localhost:8080/place/test , I only get the Google Chrome Offline Web Page.

=> What am I missing there ? (does it have to do with nodeJs ? with the localhost environment ? with my implementation ?)

I've been struggling with this one for a little while now...

I have checked in the "Application" tab and my service worker shows up as activated and is running.

Note : If found a similar question here, but no satisfying answer over there : Service worker not run in offline mode using nodejs server

like image 417
B. B. Avatar asked Aug 27 '17 17:08

B. B.


1 Answers

Fundamentally this is the same problem as answered here: Service worker is caching files but fetch event is never fired

If you look in your console, you'll see that while the install, activate, caching, and registration all happen, the "fetch" won't. This is because you located the service worker under js, so for security reasons Chrome (etc) won't use it for any URLs except those in the same directory or below.

If you place your client.js and service-worker.js at the same level rather than in a js subdirectory, it will all start working. That will necessitate updating the contents of the files, which I will show below for reference.

One tiny caveat: I foolishly used IIS on a Windows box to work on this, and between that and Chrome they clung like grim death to the cached HTML files with outdated JS-file locations. I had to copy them into a subdirectory, making fresh URLs, to test the solution.

index.html:

<head>
<script src="client.js"></script>
</head>
<body>
<a href="cachetest.html">link to ct</a>
</body>

cachetest.html:

<head>
<script src="client.js"></script>
</head>
<body>cachetest</body>

client.js:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker
             .register('service-worker.js')
             .then(function() { console.log('Service Worker Registered'); });
}

serviceworker.js:

var cacheName = 'myCacheVersion';
var filesToCache = [
    '',
    'cachetest.html',
    'client.js',
    'service-worker.js',
//    "css/style.css"
];


self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== cacheName) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
  );
  return self.clients.claim();
});

self.addEventListener('fetch', function(e) {
  console.log('[ServiceWorker] Fetch', e.request.url);
  e.respondWith(
    caches.match(e.request).then(function(response) {
      return response || fetch(e.request);
    })
  );
});
like image 64
Ed. Avatar answered Sep 21 '22 23:09

Ed.