Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service Worker skipWaiting unable to activate currently waiting SW

Description:

We are using sw precache for caching the scripts before hand, hence to update the scripts we are giving reload option, for that we are listening the worker message to skip waiting the newly install service worker for unknown reason we are not getting correct

importScript

// GETTING OLD SW reference (self) and NOT getting newly installed SW reference

self.addEventListener('message', function(event) {
    *// not working*
    self.skipWaiting();
});



// But if we put skipWaiting() in 'install' listener 
// it is getting correct new SW reference and working correctly

self.addEventListener('install', function(event) {
    // self.skipWaiting();
});

SW registration

if('serviceWorker' in window.navigator) {
      window.addEventListener('load', function() {
        window.navigator.serviceWorker.register("/serviceWorker.js").then(function(registration) {
          console.log("ServiceWorker registration successful with scope: ", registration);
          registration.onupdatefound = function() {
            console.log('NEW WILD WORKER HAS SPAWNED.!', registration);
            var installedWorker = registration.installing;
            installedWorker.onstatechange = function() {
              if (installedWorker.state === 'installed') {
                if (navigator.serviceWorker.controller) {
                  console.log('Updated content is available RELOAD!', navigator.serviceWorker.controller);
                  var el = document.getElementById('feature');
                  el.style['display'] = 'block';
                }
              }
            }
          }
        }).catch(function(error) {
          console.error("ServiceWorker registration failed: ", error);
        });
      });
      window.navigator.serviceWorker.addEventListener('controllerchange', function() {
        console.log('SERVICE WORKER UPDATED');
      });
    }

webpack config

new SWPrecacheWebpackPlugin({
        cacheId: 'pwa',
        filename: 'serviceWorker.js',
        staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/, /_nch\.[0-9a-z]+\.[js, css]+/g, /webpackManifest\.[0-9a-z]+\.js/g, /.DS_Store\.[0-9a-z]+/g],
        importScripts: ['offline/offline.1a2b3c4df1.js'],
        dontCacheBustUrlsMatching: /./,
        minify: false,
        skipWaiting: false,
        runtimeCaching: [ {
          urlPattern: /_nch\.[0-9a-z]+\.[js, css]+/g,
          handler: 'fastest',
          options: {
            cache: {
              name: 'jd-internal-script',
              maxEntries: 10,
            },
          },
        }, {
          urlPattern: /webpackManifest\.[0-9a-z]+\.js/g,
          handler: 'networkFirst',
          options: {
            cache: {
              name: 'jd-root-doc',
            },
          },
        }],
      }),
like image 275
Anurag Singh Avatar asked Sep 21 '17 16:09

Anurag Singh


People also ask

What is skipWaiting service worker?

skipWaiting() method of the ServiceWorkerGlobalScope forces the waiting service worker to become the active service worker. Use this method with Clients. claim() to ensure that updates to the underlying service worker take effect immediately for both the current client and all other active clients.

How do I activate a service worker?

Updating your service workerIt is only activated when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more such pages still loaded, the new service worker activates. While this happens, the previous version is still responsible for fetches.


1 Answers

The best documentation for skipWaiting() can be found at https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#skip_the_waiting_phase

You can either call it unconditionally in the install handler, or follow the model that you seem to be doing, which is to listen for a message event and call skipWaiting() conditionally.

If you go the conditional route, then you should modify your client page's code to properly detect when the service worker you're registering enters the waiting state, and give the user the option of interacting with the page in a way that results in a corresponding postMessage() to tell the service worker to skipWaiting(). Based on what you're saying, you've tried this, but it looks like you're sending the message to the wrong service worker instance.

Here's what you page's code should look like:

// On your page:
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js').then(function(reg) {
      reg.onupdatefound = function() {
        var newSW = reg.installing;
        newSW.onstatechange = function() {
          if (newSW.state === 'waiting') {
            // This assumes there's a button with id='skip-waiting-button' that
            // users should click to get the new SW to activate immediately.
            var button = document.querySelector('#skip-waiting-button');
            button.addEventListener('click', function() {
              newSW.postMessage('skipWaiting');
            });
            // Assume that 'display' is 'none' initially.
            button.style.display = 'inline';
          }
          // Handle whatever other SW states you care about, like 'active'.
        };
      };
    })
  });
}

// In your service worker:
self.addEventListener('message', event => {
  if (event.data === 'skipWaiting') {
    self.skipWaiting();
  }
});
like image 169
Jeff Posnick Avatar answered Oct 22 '22 18:10

Jeff Posnick