Messaging between Service Worker and Angular component

Most of the time service worker logic and application logic work in isolation, but there will be cases where we need to pass messages between them. For example we are using background sync and to let the application know that it is complete, we can send a message from service worker and receive it in the application. In this post we’ll see how we can do this in an angular application.

Prerequisite

  1. Basic understanding of Angular application architecture.
  2. Basic understanding of PWA and service workers.
  3. VS Code and @angular/cli installation.

Basic Workflow

  • On button click we'll create a message with property type and value FROM_APP and send it to the service worker.
  • In service worker we'll create a event handler to listen to messages and filter messages with type FROM_APP.
  • From service worker send acknowledgement message back to client with property type and value FROM_SW.
  • In the angular component receive the acknowledgement and print it to the console.

Send Message from Angular

To send message from angular we will be using postMessage method of ServiceWorker. postMessage signature is similar to that of Client.postMessage. Unfortunately I couldn't find its documentation in the MDN site.

navigator.serviceWorker.controller.postMessage({
    type: 'FROM_APP'
});

Create event handler to accept message from service worker.

Here we'll be adding the handler to ServicWorkerContainer message event.

navigator.serviceWorker.onmessage = (event)=>{
    if(event.data && event.data.type === 'FROM_SW') {
        console.log('Message received from SW');
    }
}

Receive message in service worker

In service worker we can create an event handler to the message event that will filter messages with type FROM_APP.

self.addEventListener('message', (event) => {
    if (event.data && event.data.type === 'FROM_APP') {
        console.log('message received from app');                   
    }
});

Send acknowledge to the parent page

To send acknowledge message we need to identify the last focused tab. We can use the matchAll method for that. This method (Chrome 46/Firefox 54 and later) returns clients in most recently focused order.

self.clients.matchAll().then((clients) => {
    if (clients && clients.length) {
        //Respond to last focused tab
        clients[0].postMessage({ type: 'FROM_SW' });
    }
});

Conclusion

Even though service worker communication and its implementation are easy, it is very difficult to get relevant documentation regarding events and available methods. Referring Mozilla documentation is a good start, but it is not complete. You can also refer 'How to communicate with Service Workers' article written by Felix Gerschau for more information.