How to add FCM (Firebase Cloud Messaging) to VueJS 
Tags: vue, webdev, firebase
Published: 2021-03-08 17:09:15

Lately I had a task to implement FCM (Firebase Cloud Messaging) to a vue application I am working on, and I've found out that there are few guides but they didn't helped me too much because FCM's API, vue cli and vue it self were updated since then, so I've decided to write down a small and updated guide for it. 

#Step 1 - Add the service worker file
The first thing that we need to do is to add the service worker file `firebase-messaging-sw.js` to the `public` folder (It's important to use this file name because firebase will look for this file with that specific name, it can be changed tough but not in this guide - sorry).
(If you are not familiar with the words 'service worker' you can learn more about it [Here](https://developers.google.com/web/fundamentals/primers/service-workers) or [Here](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker))

```js
//firebase-messaging-sw.js

importScripts('https://www.gstatic.com/firebasejs/8.2.7/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/8.2.7/firebase-messaging.js')

var firebaseConfig = {
  apiKey: <API-KEY>,
  authDomain: <AUTH-DOMAIN>,
  projectId: <PROJECT-ID>,
  storageBucket: <STORAGE-BUCKET>,
  messagingSenderId: <MESSAGING-SENDER-ID>,
  appId: <APP-ID>,
  measurementId: <MEASUREMENT-ID>
}

const app = firebase.initializeApp(firebaseConfig)
```
> **Replace the config json above with the one you got from firebase**
> Go to your project home page at firebase -> Press on the Settings icon -> click 'Project Settings' -> Scroll down -> `firebaseConfig` object

#Step 2 - Register the service worker
The next step is to register the service worker.
We have few ways of doing that:

####* If you prefer using firebase package jump to Step 3.

###* Using vue cli's PWA plugin
If you've created your application through vue cli (v3+) and you've added the PWA support option (or added this plugin manually after the installation) you can register the service worker with `registerServiceWorker.js` file as follows:
```js
//registerServiceWorker.js

import { register } from 'register-service-worker'

register('firebase-messaging-sw.js')
``` 
> You can learn more about the above plugin and its events [Here](github.com/yyx990803/register-service-worker)

###* Using vanilla JS
If you prefer to register the service worker using only JS, you can add the following code (anywhere in your application):
```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('firebase-messaging-sw.js')
    .then(reg => {
      console.log(`Service Worker Registration (Scope: ${reg.scope})`);
    })
    .catch(error => {
      const msg = `Service Worker Error (${error})`;
      console.error(msg);
    });
} else {
  // happens when the app isn't served over HTTPS or if the browser doesn't support service workers
  console.warn('Service Worker not available');
}
```


#Step 3 - Using firebase module
Another way to register the service worker and subscribe to FCM is by installing the firebase package.
`npm install firebase`
After you've installed the package, create a file called `firebase.js` (or any other name you want) and add the following:
```js
//firebase.js

import firebase from 'firebase/app'
import 'firebase/firebase-messaging'

var firebaseConfig = {
  apiKey: <API-KEY>,
  authDomain: <AUTH-DOMAIN>,
  projectId: <PROJECT-ID>,
  storageBucket: <STORAGE-BUCKET>,
  messagingSenderId: <MESSAGING-SENDER-ID>,
  appId: <APP-ID>,
  measurementId: <MEASUREMENT-ID>
}

firebase.initializeApp(firebaseConfig)

export default firebase.messaging()
```
####Why do I need to instanciate firebase again? I already did it on step 1...
Because the service worker is running on another thread and not on the main one, therefor we cannot pass the instance to our main application.

###Add FCM in vue 2
To add FCM as a global in your vue 2 application go to your `main.js` file and add the following:
```js
//main.js

...
import firebaseMessaging from './firebase'

Vue.prototype.$messaging = firebaseMessaging

new Vue({
...
```
Now you can access FCM instance everywhere in your application by calling `this.$messaging`.

###Add FCM in vue 3
####Add as a global
You can add FCM as a global in vue 3 but then it **won't** be accessible in composition's API `setup()` method.
```js
//main.js

...
import firebaseMessaging from './firebase'

const app = createApp(App)

app.config.globalProperties.$messaging = firebaseMessaging

app.mount('#app')
```
Now you can call it in every component:
```js
//RandomComponent.vue

...
  mounted () {
    console.log('Firebase cloud messaging object', this.$messaging)
  }
...
```


####Use Provide/Inject
Another way that vue 3 is providing to pass data is the Provide/Inject feature. (You can learn more about it [Here](https://v3.vuejs.org/guide/component-provide-inject.html#working-with-reactivity))
In your `App.vue` (or any other component you want the 'Super Parent' to be) add the following:
```js
//App.vue

...
<script>
import { provide } from 'vue'
import firebaseMessaging from './firebase'

export default {
  //options api
  provide: {
    messaging: firebaseMessaging
  }
  //composition api
  setup() {
    provide('messaging', firebaseMessaging)
  }
}
</script>
...
```
And Now you can call it by injecting it into any child component you want, for example:
```js
//RandomChildComponent.vue

...
<script>
import { inject } from 'vue'

export default {
  //options api
  inject: ['messaging'],
  mounted () {
    console.log('Firebase cloud messaging object', this.$messaging)
  }
  //composition api
  setup() {
    const messaging = inject('messaging')

    console.log('Firebase cloud messaging object', messaging)
  }
}
</script>
...
```


#Step 4 - Subscribe
After the service worker has been registered we can subscribe our client to FCM by calling the `getToken()` function.
Go back to `firebase-messaging-sw.js` (if you used step 2) or call firebase's `messaging` object (if you used step 3) and add the following code:
```js
...
//firebase-messaging-sw.js (step 2)
app.messaging().getToken({ vapidKey: <KEY> })

//RandomChildComponent.vue (step 3)
messaging.getToken({ vapidKey: <KEY> })
...
```
To get the vapidKey go to firebase console:
> Go to your project home page at firebase -> Press on the Settings icon -> click 'Project Settings' -> 'Cloud Messaging' tab -> 'Web configuration' > 'Web Push certificates'

* In case you want to get the specific token of each client you can add the following to your `getToken()` function:
```js
app.messaging().getToken({ vapidKey: <KEY> })
.then((currentToken) => {
  if (currentToken) {
    console.log('client token', currentToken)
  } else {
    console.log('No registration token available. Request permission to generate one.');
  }
}).catch((err) => {
  console.log('An error occurred while retrieving token. ', err);
})
```

#####In case you used step 3 (firebase package) `getToken()` method will also register the service worker for you.
####The `getToken()` function will subscribe to FCM and since this moment your client will get push notification from FCM. yey :)

Hope it helped you somehow, enjoy :)