Persiapan
Buat Proyek vue-vuetify-pwa
vue create vue-vuetify-pwa


Install Vuetify Theme
vue add vuetify
Install Firebase into Vue Project
npm install firebase --save
Buat Project di FireBase
Sebelum memulai membuat Program, kita akan menyiapkan Proyek di Firebase, masuk ke Firebase Console buat Proyek baru, setelah selesai masuk ke Menu Project Overview => Setelan proyek

Menambahkan Firebase ke Aplikasi Web

Sekarang kita akan membuat setingan untuk firebase di Program Vue kita sesuaikan dengan gambar di atas. Buka main.js tambahkan baris berikut diantara import dan Vue.config.productionTip = false;
import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; import "./registerServiceWorker"; import vuetify from './plugins/vuetify'; import firebase from 'firebase/app'; import '@firebase/messaging'; const firebaseConfig = { apiKey: "AIzaxxxxxxxxxxxxxxxxxxxxx_xxxxxM3tRDNPc", authDomain: "vue-firebase-xxxxx.firebaseapp.com", databaseURL: "https://vue-firebase-xxxxx.firebaseio.com", projectId: "vue-firebase-xxxxx", storageBucket: "vue-firebase-xxxxx.appspot.com", messagingSenderId: "8142xxxxx626", appId: "1:8142xxxxx626:web:a313b9d16f14abb0fdb383" }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); messaging.usePublicVapidKey("BASZxxxxxxxxxxxxxxx2tlVbCLpQ-F1nlfv9J0nOLF6457jgltDDLt-xxxxxxxxxxxxxx-K7NaBcCJqHbuPwf-o"); // 1. Generate a new key pair // Request Permission of Notifications messaging.requestPermission().then(() => { console.log('Notification permission granted.'); // Get Token messaging.getToken().then((token) => { console.log(token) }) }).catch((err) => { console.log('Unable to get permission to notify.', err); }); messaging.onMessage((payload) => { console.log('Message received. ', payload); // ... }); Vue.config.productionTip = false; new Vue({ firebase, router, store, vuetify, render: h => h(App) }).$mount("#app");
npm install firebase --save
Menyiapkan Route
router.js
import Vue from "vue"; import Router from "vue-router"; import Home from "./views/Home.vue"; import Login from "./views/Login.vue"; import Profile from "./views/Profile.vue"; import Todos from "@/views/Todos"; import store from "./store.js"; Vue.use(Router); let router = new Router({ mode: "history", base: process.env.BASE_URL, routes: [ { path: "/home", name: "Home", component: Home, meta: { auth: true } }, { path: '/about', name: 'about', component: () => import('./views/About.vue'), meta: { auth: true } }, { path: "/", name: "Login", component: Login, meta: { guest: true } }, { path: "/profile", name: "Profile", component: Profile, meta: { //auth: true } }, { path: '/todo', name: 'Todos', component: Todos, meta: { auth: true } } ] }); router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.auth)) { if (store.state.isLogin) { next(); } else { next({ path: "/", }); } } else if (to.matched.some(record => record.meta.guest)) { if (store.state.isLogin) { next({ path: "/profile", }); } else { next(); } } else { next(); } }); export default router;
Menyiapkan Store
Kita perlu menyiapkan store untuk menyimpan status login & data user yang nantinya akan ditampilkan pada component Profile.vue
import Vue from "vue"; import Vuex from "vuex"; import todo from './modules/todo'; Vue.use(Vuex); export default new Vuex.Store({ state: { isLogin: false, user:null, }, mutations: { resetState (state) { state.isLogin=false; state.user=null; } }, actions: { clearState ({ commit }) { commit('resetState'); }, }, modules: { todo, } });
Login component menggunakan FirebaseUI
FirebaseUI adalah library yang dibuat sebagai tambahan dari Firebase Authentication SDK yang menyediakan alur UI drop-in untuk digunakan dalam aplikasi Anda. Baca penjelasannya disini.
Sekarang kita akan menambahkan FirebaseUI di program Vue kita
npm install firebaseui --save
Karena kita akan login menggunakan gmail atau email, maka kita harus mengaktifkan options Authentication pada Firebase Console. Masuk ke Menu Authentication=>Pilih Tab Metode Login lalu aktifkan pilihan Email & Google

Setelah itu kita buat component Login.vue yang nantinya akan menampilkan halaman login.
<template> <div> <v-container> <v-row> <v-col cols="2" md="4"></v-col> <v-col cols="8" md="4"> <br/><br/> <v-sheet class="text-center" elevation="3" > <br/><br/> <section id="firebaseui-auth-container"></section> <br/><br/> </v-sheet> </v-col> <v-col cols="2" md="4"></v-col> </v-row> </v-container> </div> </template> <script> import firebase from 'firebase/app'; import 'firebase/auth'; import 'firebase/messaging'; import * as firebaseui from "firebaseui"; import "firebaseui/dist/firebaseui.css"; export default { name: "Login", data() { return {}; }, created() { firebase.auth().onAuthStateChanged(user => { if (user) { this.$store.state.isLogin=true; this.$store.state.user=user; this.user=this.$store.state.user; this.$router.push('/profile'); } }); }, mounted() { let ui = firebaseui.auth.AuthUI.getInstance(); if (!ui) { ui = new firebaseui.auth.AuthUI(firebase.auth()); } var uiConfig = { signInSuccessUrl: "/profile", signInFlow: "popup", signInOptions: [ //firebase.auth.FacebookAuthProvider.PROVIDER_ID, firebase.auth.GoogleAuthProvider.PROVIDER_ID, firebase.auth.EmailAuthProvider.PROVIDER_ID ] }; ui.start("#firebaseui-auth-container", uiConfig); } }; </script> <style> </style>
Perhatikan baris signInSuccessUrl: “/profile”, Jika login berhasil route akan diarahkan ke route /profile.
Buat NavBar
Selanjutnya kita akan membuat sebuah component NavBar.vue yang nantinya bisa diakses di setiap component jika dalam posisi login
components/NavBar.vue
<template> <section> <v-navigation-drawer v-model="drawer" app> <v-list-item> <v-list-item-content> <v-list-item-title class="title"> Application Name </v-list-item-title> <v-list-item-subtitle> subtext </v-list-item-subtitle> </v-list-item-content> </v-list-item> <v-divider></v-divider> <v-list dense nav> <v-list-item to="/Home"> <v-list-item-action> <v-icon>mdi-home</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Home</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item to="/About"> <v-list-item-action> <v-icon>mdi-help-circle</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>About</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item to="/ToDo"> <v-list-item-action> <v-icon>mdi-clipboard-list-outline</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>ToDo List</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> <v-divider></v-divider> <v-list dense nav> <v-list-item to="/Messages"> <v-list-item-action> <v-badge> <template v-slot:badge>0</template> <v-icon>mdi-email</v-icon> </v-badge> </v-list-item-action> <v-list-item-content> <v-list-item-title>Messages</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> <template v-slot:append> <div class="pa-2"> <v-btn @click="signoutButtonPressed" color="red darken-4 white--text" block>Logout</v-btn> </div> </template> </v-navigation-drawer> <v-app-bar app color="blue darken-4" dark> <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon> <v-toolbar-title>Application</v-toolbar-title> <div class="flex-grow-1"></div> <v-btn icon> <v-icon>mdi-heart</v-icon> </v-btn> <v-menu left bottom> <template v-slot:activator="{ on }"> <v-btn icon v-on="on"> <v-icon>mdi-dots-vertical</v-icon> </v-btn> </template> <v-list> <v-list-item to="/Profile"> <v-list-item-action> <v-icon>mdi-account-circle</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Profile</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item to="/Setting"> <v-list-item-action> <v-icon>mdi-settings</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title>Setting</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> </v-menu> </v-app-bar> </section> </template> <script> import firebase from 'firebase/app'; import 'firebase/auth'; export default { props: { source: String, }, data: () => ({ drawer: null, }), created() { firebase.auth().onAuthStateChanged(user => { if (!user&&this.$route.name!='Login') { this.$router.push('/'); } }); }, methods: { signoutButtonPressed(e) { e.stopPropagation(); firebase.auth().signOut(); this.$store.dispatch('clearState'); } }, }; </script>
Buat Layout
Buat layout pada App.vue
<template> <v-app teal> <NavBar v-if="getStatusLogin"/> <v-content> <router-view /> </v-content> <v-footer color="blue darken-4" app> <span class="white--text">© 2019</span> </v-footer> </v-app> </template> <script> import NavBar from "./components/NavBar"; import firebase from 'firebase/app'; import 'firebase/auth'; export default { name: "App", components: { NavBar }, data: () => ({ // }), computed: { getStatusLogin: function () { console.log(this.$store.state.isLogin); return this.$store.state.isLogin; } } }; </script>
perhatikan baris <NavBar v-if=”getStatusLogin”/> component ini hanya akan tampil jika posisi user login dimana getStatusLogin diambil dari store.
Buat View
Views/Profile.vue
<template> <section> <v-container class="pa-2" fluid> <v-row> <v-col> <v-card color="#385F73" dark> <v-card-text v-if="user" class="white--text"> <v-avatar><img :src="user.photoURL" alt="avatar"></v-avatar> <div class="headline mb-2" v-if="user">{{user.displayName}}</div> <p> name:<strong>{{user.displayName}}</strong> <br />email: <strong>{{user.email}}</strong> <br />uid: <strong>{{user.uid}}</strong> <br />provider: <strong class="teal-text">{{user.providerData[0].providerId}}</strong> </p> </v-card-text> <v-card-actions> <v-btn text>Listen Now</v-btn> </v-card-actions> </v-card> </v-col> </v-row> </v-container> </section> </template> <script> import firebase from 'firebase/app'; import 'firebase/auth'; export default { data: () => ({ user:null, result:null, errors:null }), created() { firebase.auth().onAuthStateChanged(user => { if (user) { this.$store.state.isLogin=true; this.$store.state.user=user; this.user=this.$store.state.user; } }); }, } </script>
Initialize a Firebase project
Untuk menginisialisasi bahwa proyek ini menggunakan firebase
firebase init
Sehingga struktur direktori akan menjadi sbb:
Proyek akan di build di direktori dist

Setting Firebase Message
Tambahkan file firebase-messaging-sw.js pada folder public, isi program seperti di bawah ini:
// [START initialize_firebase_in_sw] // Give the service worker access to Firebase Messaging. // Note that you can only use Firebase Messaging here, other Firebase libraries // are not available in the service worker. importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js'); importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-messaging.js'); // Initialize the Firebase app in the service worker by passing in the messagingSenderId. firebase.initializeApp({ 'messagingSenderId': '81422xxxxx26' // 4. Get Firebase Configuration }); // Retrieve an instance of Firebase Messaging so that it can handle background messages. const messaging = firebase.messaging(); // [END initialize_firebase_in_sw] messaging.setBackgroundMessageHandler(function(payload) { console.log('[firebase-messaging-sw.js] Received background message ', payload); // Customize notification here const notificationTitle = 'Background Message Title'; const notificationOptions = { body: 'Background Message body.', icon: '' }; return self.registration.showNotification(notificationTitle, notificationOptions); });
Sesuaikan messagingSenderId dengan Firebase anda.
Build Proyek
PWA hanya akan berjalan di server distribution, build proyek anda:
npm run build
Tambahkan redirect
Tambahkan baris berikut pada router.js
{ path: "/index.html", redirect: "/" }
Deploy
firebase deploy
Dapatkan Token Firebase

Test Send Notification

sumber: