Search code examples
javascriptservice-workerofflineoffline-caching

ServiceWorker blocks any external resource


I've implemented ServiceWorker on some of my webapps to leverage offline capabilities and some other goodies related to the ServiceWorkers. Now, everything is working fine until I have added some external embedded scripts. There are about 3 external scripts that I've added on my webapp. Some of which fetch ads and display it on my app and some of which are used to gather analytics.

But, to my surprise, every external scripts are failing when the ServiceWorkers are enabled and throws below error in the console

enter image description here

I'm not sure why is this happening? Do I have to cache these scripts some way in ServiceWorker? Any help would be appreciated.

Here is my ServiceWorker code that I've added on my app.

importScripts('js/cache-polyfill.js');

var CACHE_VERSION = 'app-v18';
var CACHE_FILES = [
    '/',
    'index.html',
    'js/app.js',
    'js/jquery.min.js',
    'js/bootstrap.min.js',
    'css/bootstrap.min.css',
    'css/style.css',
    'favicon.ico',
    'manifest.json',
    'img/icon-48.png',
    'img/icon-96.png',
    'img/icon-144.png',
    'img/icon-196.png'
];

self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open(CACHE_VERSION)
            .then(function (cache) {
                console.log('Opened cache');
                return cache.addAll(CACHE_FILES);
            })
    );
});

self.addEventListener('fetch', function (event) {
    event.respondWith(
        caches.match(event.request).then(function(res){
            if(res){
                return res;
            }
            requestBackend(event);
        })
    )
});

function requestBackend(event){
    var url = event.request.clone();
    return fetch(url).then(function(res){
        //if not a valid response send the error
        if(!res || res.status !== 200 || res.type !== 'basic'){
            return res;
        }

        var response = res.clone();

        caches.open(CACHE_VERSION).then(function(cache){
            cache.put(event.request, response);
        });

        return res;
    })
}

self.addEventListener('activate', function (event) {
    event.waitUntil(
        caches.keys().then(function(keys){
            return Promise.all(keys.map(function(key, i){
                if(key !== CACHE_VERSION){
                    return caches.delete(keys[i]);
                }
            }))
        })
    )
});

Solution

  • Here's what I did to resolve the issue.

    I tried checking if the app is online or not using Navigator.onLine API in the fetch event listener and if it's online, then serve the response from the server and from ServiceWorker otherwise. This way the requests won't get blocked while the app is online and thus resolves this particular issue.

    Here's how I've implemented it.

    self.addEventListener('fetch', function (event) {
        let online = navigator.onLine;
        if(!online){
          event.respondWith(
              caches.match(event.request).then(function(res){
                  if(res){
                      return res;
                  }
                  requestBackend(event);
              })
          )
        }
    });
    

    You could also check the entire ServiceWorker script here: https://github.com/amitmerchant1990/notepad/blob/master/sw.js