Search code examples
javascriptservice-workerservice-worker-events

serviceWorker 'activate' and 'message' events not firing


I'm trying to use serviceWorkers for the first time, and even though it started well, I'm a little stuck..

Here's my very simple service-worker.js:

self.addEventListener('install', () => {
  console.log('Hello world from the Service worker')
})

self.addEventListener('activate', () => {
  console.log('Serive worker now active')
})

self.addEventListener('message', event => {
  console.log('Service worker received message ' + JSON.stringify(event))
})

I register for the service worker like so:

useEffect(() => {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker
        .register('/service-worker.js')
        .then(() => {
          console.log('Service worker registration successful')
        })
        .catch(e => {
          console.error('Service worker registration failed: ' + e)
        })
    }
  }, [])

As I load my app, I get the following logs:

Service worker registration successful // APP
Hello world from the Service worker // SERVICE WORKER install event

So, I do get the install event called, but not the activate event.

Also, when I send a message to the service worker from my app:

navigator.serviceWorker.controller.postMessage({test: 'test'})

the message event on the service worker doesn't get called either...

Is there something wrong I'm doing? Doesn't the service worker activate somehow?

For additional context, my app uses Next.js, and I place the service-worker.js in the public folder in my project.

Also, on the app, if I try posting the message like this:

navigator.serviceWorker.ready.then(registration => {
  console.log(registration.active)
  registration.active.postMessage({test: 'test'})
})

I get logged the instance of the service worker, (I assume) meaning that the service worker is indeed active/ready.


Solution

  • ServiceWorkerRegistration.active isn't immediately available, so the instance should be obtained with installing or waiting first. skipWaiting() could be used when the SW is updated/modified since last installation.

    // main.js
    
    navigator.serviceWorker?.register('./service-worker.js')
      .then(reg  => {
        console.log('registered', reg)
        const sw = reg.installing || reg.waiting || reg.active
        sw.postMessage({ milliseconds: Date.now() })
      })
      .catch(() => console.error('registration failed'))
    
    // service-worker.js
    
    self.addEventListener('install', e => {
      console.log(e.type)
      self.skipWaiting() // always activate updated SW immediately
    })
    
    self.addEventListener('activate', e => console.log(e.type))
    
    self.addEventListener('message', e => console.log(e.type, e.data))