Firebase (FCM) — Web Push Notifications: With changed or custom location of Service Worker

Sanjeev Pandey
3 min readMar 30, 2021

--

In my attempt to integrate Firebase cloud messaging (aka push notification) into my web app, I stumbled onto a problem where my local tests were working fine however after I hosted the app as static site, the flow broke since app wasn’t able to register the service worker correctly — in fact it wouldn’t even point to the correct file location as it would pick the root (my site’s hostname) as the location of the service worker whereas in fact it was located at a path instead of directly at the root.

I found that the same problem existed when I hosted the web-app on a compute environment and served as node app.

After researching on StackOverflow, medium.com, Google’s own docs and other sites for the problem, and looking into various similar issues opened by other developers who tried to implement this before me, and also looking at FCM Quickstart reference on Github, I concluded that while people were able to use these sources to solve their implementation issues like me, there wasn’t a single source or sample explaining this particular problem in detail, all in one place. So, I decided to write one up — a single page explaining the nuances of this implementation. What this article is not — a source elaborating the basics and methods of FCM, rather I will focus on this specific type of implementation — and only this — with the end goal of hosting this web-app as a static site and maybe as a site served as a node.js app.

If you’re reading this, I take it that you’ve already done your initial setup on Firebase Console. If not, follow this easy guide from FCM docs.

So, how do you register a service worker that is on a changed / non-default / non-absolute path? Answer lies in these three simple steps:

#1

You need to first pass the location of service worker to navigator.serviceWorker.register() and then use that registration for messaging class's useServiceWorker method. An example would be:

// obtain messaging class from Firebase 
const messaging = firebase.message();
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./path/service-worker.js')
.then((registration) => {
messaging.useServiceWorker(registration);
// request notification permission and get token
console.log('Registration successful, scope is:',
registration.scope);
//TODO: ask For Permission To Receive Notifications
}).catch(function(err) {
console.log('Service worker registration failed, error:', err); });
}

This would take care of pointing the app to correct (and non-default) location of your service worker.

#2

Note that the location of the service worker that you are giving in the code above is relative to your main html file (generally index.html). Consider the below file-tree example for clarity:

|- index.html

|- service-worker.js

|- /path/push-notification.js (file that contains the code to register service worker)

So, in above scenario even though you are putting the code to register service worker in /path/push-notification.js, since the service-worker.js is in the same directory as index.html, the path given for service worker in push-notification.js will look like below, which is relative to index.html and not to the push-notification.js itself:

navigator.serviceWorker.register('service-worker.js')

#3

Next step is to make sure to init the Firebase app in your service worker — a quick way to do that is to put your init code in a separate file and importScript it in your service worker:

importScripts('./assets/js/init-firebase.js')

That’s it — solved! Now your app will get the service worker from the location you have specified, and register it, and your service worker won’t throw errors like missing project-id or script evaluation failed etc. since the Firebase app will already be initialized in it.

Update: I have used the deprecated method of useServiceWorker() above but, it does the trick. An updated approach would be to use getToken(options?: {vapidKey?: string; serviceWorkerRegistration?: ServiceWorkerRegistration;}: Promise; ; for which the implementation will change.

Clap 👏 & subscribe if you liked the article! Happy coding!

Originally published at http://sanjeevkumarpandey.wordpress.com on March 30, 2021.

--

--

Sanjeev Pandey

Co-Founder of <indvideotech> community for Video Engineers in India. Solution Architect, Full-Stack Developer, Ad Insertion Evangelist, and Think Tank.