question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Document the event handler created by workbox-core's clientsClaim()

See original GitHub issue

Library Affected: workbox-sw, workbox-window

Browser & Platform: all browsers

Issue or Feature Request Description:

I’m following the “Offer a page reload for users” from “Advanced Recipes”. The sample code suggest to listen to the WB controlling event and then perform the reload. This event is never triggered for me.

When I change it to activated it works.

Is this an error in the docs or am I doing something wrong?

When reporting bugs, please include relevant JavaScript Console logs and links to public URLs at which the issue could be reproduced.

service-worker.js:

// …
addEventListener('message', event => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    skipWaiting();
  }
});
// …

service-worker-registration.js:

const wb = new Workbox('/sw.js');
wb.addEventListener('waiting', event => {
  if (alert('Everything is new. Wanna see?')) {
    wb.addEventListener('controlling', event => {
      // will never be called
      window.location.reload();
    }
    wb.messageSW({ type: 'SKIP_WAITING' });
  }
});
wb.register();

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:16 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
jeffposnickcommented, Mar 18, 2021

@hannandesai: Just a few random comments:

I had some issues getting your code to compile as-is, because you’re doing things like const path = require("path"); inside of a service worker, which won’t work. I’m assuming you have something custom in your build process that somehow translates that into code that will run inside of the ServiceWorkerGlobalScope, but I’m not sure what it is. So I pared down your sample code a bit instead of running it directly.

But in any case, I see some problems with the following code:

    wb.addEventListener('waiting', (event) => {
      console.info(`A new service worker has installed, but it can't activate` +
        `until all tabs running the current version have fully unloaded.`);
      if (serviceWorker && serviceWorker.waiting) {
        serviceWorker.waiting.addEventListener("controlling", (event) => {
          console.log("controlling")
          messageSW(event.sw, { type: "APP_VERSION_UPDATE" });
        })
        wb.messageSkipWaiting();
      }
    });

In this case, serviceWorker.waiting is an instance of ServiceWorker, not of Workbox. There’s no event called controlling that is ever fired on a ServiceWorker, so listening for that won’t accomplish anything.

A Workbox object can listen for controlling events, though (it’s one of the “synthetic” events that workbox-window dispatches), so that’s what I assume you intended to do.

In the course of exploring this issue, though, I realized that the Workbox object’s controlling event isn’t dispatched if the new service worker that takes control isn’t the same as the service worker that originated from the register() method. That’s a bug—we should fire controlling in either case, with the isExternal property set to true or false—and I created #2786 to track that.

So, once #2768 is resolved, you should be able to write:

const wb = new Workbox('sw.js');

// Set up your event listeners for waiting, conditionally call messageSkipWaiting(), etc.

// Listen for changes to navigator.serviceWorker.controller:
wb.addEventListener('controlling', (event) => {
  if (event.isExternal) {
    // A new service worker is in control that wasn't associated with the original registration.
    // This will happen if the new service worker was detected via wb.update().
  } else {
    // The service worker associated with the original registration is in control.
  }
});

wb.register();

// Don't use an interval of 1000 in production, obviously...
setInterval(() => wb.update(), 1000);

In the meantime, instead of using wb.addEventListener('controlling', () => {...}), you could just use the underlying service worker API directly to listen for the controllerchange event conditionally, only if there’s already a service worker in control (to avoid firing it when it’s the initial service worker):

if (navigator.serviceWorker.controller) {
  navigator.serviceWorker.addEventListener('controllerchange', (event) => {
    // If this executes, there was an initial service worker in control during the page load,
    // and now a service worker has taken control.
  });
}

The rest of the general logic could remain the same in that case.

1reaction
jeffposnickcommented, Mar 18, 2021

Yup, understood. I will dive into both code samples soon. I just know that clientsClaim() can be confusing to use and wanted to clarify that off the bat.

Read more comments on GitHub >

github_iconTop Results From Across the Web

workbox-core - Chrome Developers
The clientsClaim() method in workbox-core automatically adds an activate event listener to your service worker, and inside of it, ...
Read more >
Clients.claim() - Web APIs - MDN Web Docs
A Promise that resolves to undefined . Examples. The following example uses claim() inside service worker's " activate " event listener so that ......
Read more >
What are the downsides to using skipWaiting and clientsClaim ...
Workbox uses an install event handler to cache new or updated entries in the precache manifest (appending a __WB_REVISION__ query param to ...
Read more >
Handling JavaFX Events: Working with Event Handlers
Learn how event handlers can be used to process the events generated by ... The handle() method of this interface provides the code...
Read more >
Service Workers - W3C
This document was produced by a group operating under the W3C Patent ... A service worker has an associated set of event types...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found