In this codelab, you'll use a service worker to manage notifications. The instructions here assume that you're already familiar with service workers and the basics of requesting notification permission and sending notifications. If you need a refresher on notifications, see the Get started with the Notifications API codelab. To learn more about service workers, see Matt Gaunt's Introduction to service workers.
Remix the sample app and view it in a new tab
Notifications are automatically blocked from the embedded Glitch app, so you won't be able to preview the app on this page. Instead, here's what to do:
- Click Remix to Edit to make the project editable.
- To preview the site, press View App. Then press Fullscreen .
The Glitch should open in a new Chrome tab.
As you work through this codelab, make changes to the code in the embedded Glitch on this page. Refresh the new tab with your live app to see the changes.
Get familiar with the sample app and starting code
Start by looking at the live app in the new Chrome tab:
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
Click the Console tab.
Make sure that the Info option is selected in the Levels dropdown next to the Filter box.
In the DevTools console for your live app, you should see a console message:
TODO: Implement getRegistration()
.This is a message from a function stub that you will implement in this codelab.
Now let's take a look at the sample app's code in the embedded Glitch on this page.
In the embedded Glitch, take a look at
public/index.js
:There are four stubs for the functions you will implement:
registerServiceWorker
,getRegistration
,unRegisterServiceWorker
, andsendNotification
.The
requestPermission
function requests the user's permission to send notifications. If you did the Get started with the Notifications API codelab, you'll notice that itsrequestPermission
function is used here. The only difference is that it now also updates the user interface after resolving the permission request.The
updateUI
function refreshes all the app's buttons and messages.The
initializePage
function performs feature detection for service worker capability in the browser and updates the app user interface.The script waits until the page has loaded and then initializes it.
In the embedded Glitch, open
public/service-worker.js
.As the name suggests, you'll add code to the app to register this file as a service worker.
Although the file is not yet in use by the app, it contains some starting code that will print a message to the console when the service worker is activated.
You'll add code to
public/service-worker.js
to handle notifications when the service worker receives them.
Register the service worker
In this step, you'll write code that runs
when the user clicks Register service worker in the app UI.
This code will register public/service-worker.js
as a service worker.
In the embedded Glitch editor, open
public/index.js
. Replace theregisterServiceWorker
function with the following code:// Use the Service Worker API to register a service worker. async function registerServiceWorker() { await navigator.serviceWorker.register('./service-worker.js') updateUI(); }
Note that
registerServiceWorker
uses theasync function
declaration to make handling promises more convenient. This lets youawait
the resolved value of aPromise
. For example, the function above awaits the outcome of registering a service worker before updating the UI. Seeawait
on MDN for more information.Now that the user can register a service worker, you can get a reference to the service worker registration object. In
public/index.js
, replace thegetRegistration
function with the following code:// Get the current service worker registration. function getRegistration() { return navigator.serviceWorker.getRegistration(); }
The function above uses the Service Worker API to get the current service worker registration, if it exists. It makes getting a reference to the service worker registration a bit more convenient.
To complete the service worker registration functionality, add code to unregister the service worker. Replace the
unRegisterServiceWorker
function with the following code:// Unregister a service worker, then update the UI. async function unRegisterServiceWorker() { // Get a reference to the service worker registration. let registration = await getRegistration(); // Await the outcome of the unregistration attempt // so that the UI update is not superceded by a // returning Promise. await registration.unregister(); updateUI(); }
In the tab where you're viewing the live app, reload the page. The Register service worker and Unregister service worker buttons should now be working.
Send notifications to the service worker
In this step, you'll write code that will run when the user clicks Send a notification in the app UI. This code will create a notification, check that a service worker is registered, and then send the notification to the service worker using its postMessage
method.
In the embedded Glitch editor, open public/index.js
and
replace the sendNotification
function with the following code:
// Create and send a test notification to the service worker.
async function sendNotification() {
// Use a random number as part of the notification data
// (so you can tell the notifications apart during testing!)
let randy = Math.floor(Math.random() * 100);
let notification = {
title: 'Test ' + randy,
options: { body: 'Test body ' + randy }
};
// Get a reference to the service worker registration.
let registration = await getRegistration();
// Check that the service worker registration exists.
if (registration) {
// Check that a service worker controller exists before
// trying to access the postMessage method.
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(notification);
} else {
console.log('No service worker controller found. Try a soft reload.');
}
}
}
Here's what that code is doing:
sendNotification
is an asynchronous function, so you can useawait
to get a reference to the service worker registration.The service worker's
postMessage
method sends data from the app to the service worker. See the MDN documentation on postMessage for more information.The code checks for the presence of the
navigator.serviceWorker.controller
property before trying to access thepostMessage
function.navigator.serviceWorker.controller
will benull
if there is no active service worker, or if the page has been force refreshed (Shift+
Reload). See the ServiceWorker controller documentation on MDN for more information.
Handle notifications in the service worker
In this step, you'll write code in the service worker that will handle messages posted to it and display notifications to the user.
In the embedded Glitch editor, open public/service-worker.js
. Add the following code to the end of the file:
// Show notification when received
self.addEventListener('message', (event) => {
let notification = event.data;
self.registration.showNotification(
notification.title,
notification.options
).catch((error) => {
console.log(error);
});
});
Here's a quick explanation:
self
is a reference to the service worker itself.While the service worker now handles displaying notifications, the main app UI is still responsible for getting notification permission from the user. If permission is not granted, the promise returned by
showNotification
is rejected. The code above uses acatch
block to avoid an uncaughtPromise
rejection error and handle this error a little more gracefully.
If you got stuck, see glitch.com/edit/#!/codelab-notifications-service-worker-completed for the completed code.
Go on to the next codelab in this series: Build a push notifications server.