Search code examples
javascriptvisual-studioprogressive-web-appsservice-worker

Service-Worker is not working on offline mode


Everything seems to be right and the files are being cached but it just doesn't work offline. Am I missing something obvious?

Here is my service worker file:

// Names of the two caches used in this version of the service worker.
// Change to v2, etc. when you update any of the local resources, which will
// in turn trigger the install event again.
var PRECACHE = 'precache-v1';
var RUNTIME = 'precache-v1';
//var RUNTIME = 'runtime';

// A list of local resources we always want to be cached.
var PRECACHE_URLS = [
  '/',
  'pp-form.js',
  'pp-home.js',
  'pp.css',
  'http://localhost:8083/favicon.ico',
  'http://localhost:8083/operation/PO1',
  'http://localhost:8083/getForms/PO1/PF1',
  '/webjars/bootstrap-select/js/bootstrap-select.min.js',
  '/webjars/bowser/bowser.min.js'
];

// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', function(event) {
  console.log('install');
  event.waitUntil(
    caches.open(PRECACHE)
      .then(function(cache){
        cache.addAll(PRECACHE_URLS);
      })
      .then(self.skipWaiting())
  );
});

// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', function(event) {
    event.waitUntil(
        caches.keys().then(function(cacheNames){
            return Promise.all(
                cacheNames.map(function(cache){
                    if (cache !== PRECACHE) {
                        return caches.delete(cache); //Deleting the old cache (cache v1)
                    }
                })
            );
        })
        .then(function () {
            console.info("Old caches are cleared!");
            return self.clients.claim();
        })
    );
});

// The fetch handler serves responses for same-origin resources from a cache.
// If no response is found, it populates the runtime cache with the response
// from the network before returning it to the page.
self.addEventListener('fetch', function(event) {
  console.log('fetch');
  // Skip cross-origin requests, like those for Google Analytics.
  if (event.request.url.startsWith(self.location.origin)) {
    event.respondWith(
      caches.match(event.request).then(function(cachedResponse) {
        if (cachedResponse) {
          return cachedResponse;
        }

        return caches.open(RUNTIME).then(function(cache){
          return fetch(event.request).then(function(response) {
            // Put a copy of the response in the runtime cache.
            return cache.put(event.request, response.clone())
            .then(function() {
              return response;
            });
          });
        });
      })
    );
  }
});

navigator.connection.onchange = function(e) {
  if (navigator.onLine)
    console.log("Online");
  else
    console.log("Offline");
};

Here is registration of the service worker:

//if ('serviceWorker' in navigator) {
    if (('https:' === location.protocol || location.host.match(/(localhost|127.0.0.1)/)) && navigator.serviceWorker) {
      navigator.serviceWorker.register('/resources/pp-sw2.js');
    }

I can cache URL responses. In my project, we use: JSP, JS, and CSS.

I also noticed that if I go offline, my localhost says You're not connected. After reconnecting to the internet, I get multiple caches with the same name in PRECACHE_URLS.

Thank you in advance for any help you can provide!


Solution

  • You need a try/catch in the fetch event to handle the connection interruption.

    self.addEventListener('fetch', (event) => {
      // Only call event.respondWith() if this is a navigation request for an HTML page.
      if (event.request.mode === 'navigate') {
        event.respondWith(
          (async () => {
            try {
              // First try the cache.
              const cachedResponse = await caches.match(event.request);
              if (cachedResponse) {
               return cachedResponse;
              }
              // Then try the network.
              const networkResponse = await fetch(event.request);
              if (networkResponse) {
                return networkResponse;
              }
            } catch (error) {
              // catch is only triggered if an exception is thrown, which is
              // likely due to a network error.
              // If fetch() returns a valid HTTP response with a response code in
              // the 4xx or 5xx range, the catch() will NOT be called.
              // First try the cache.
              const cacheResponse = await caches.match(event.request);
              if (cacheResponse) {
                return cacheResponse;
              }
              // Then try the offline page
              const cache = await caches.open(cacheName);
              const offlineResponse = await cache.match(offlineUrl);
              return offlineResponse;
            }
          })()
        );
      }
      // Build cache
      let requestURL = new URL(event.request.url);
      if ((requestURL.origin == location.origin) && (event.request.method != 'POST')) {
        event.waitUntil(
          caches.open(cacheName).then(cache => {
            fetch(event.request).then(response => {
              console.log('Service Worker: Caching ' + event.request.url);
              cache.put(event.request, response.clone());
            });
          }),
        );
      }
    });