Skip to content

Instantly share code, notes, and snippets.

@echr
Last active November 23, 2023 12:05
Show Gist options
  • Save echr/a1195e083e6ff4f980698fa06ebfefc3 to your computer and use it in GitHub Desktop.
Save echr/a1195e083e6ff4f980698fa06ebfefc3 to your computer and use it in GitHub Desktop.
Simple Laravel + Vue + Laravel Mix + Firebase Notification (PWA, Offline)
// FILE PATH: /resources/js/app.js
require('./bootstrap');
// Import Service Worker Registry
require('./extensions/sw-registry');
import Vue from 'vue';
...
// FILE PATH: /resources/js/firebase.js
import * as firebase from 'firebase/app';
require('firebase/messaging');
// Change with your own Sender ID
const initializedFirebaseApp = firebase.initializeApp({
messagingSenderId: '#####'
});
let messaging = null;
if (firebase.messaging.isSupported()) {
messaging = initializedFirebaseApp.messaging();
// Change with your own VapidKey
messaging.usePublicVapidKey(
'#####'
);
messaging.onMessage((payload) => {
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: '/android-chrome-144x144.png',
}; // Your notification icon in /public directory
if (!('Notification' in window)) {
console.log('This browser does not support system notifications');
} else if (Notification.permission === 'granted') {
let notification = new Notification(notificationTitle,notificationOptions);
notification.onclick = function(event) {
event.preventDefault();
window.open(payload.notification.click_action , '_blank');
notification.close();
};
}
});
}
export { messaging };
// FILE PATH: /resources/js/service-worker.js
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/6.3.4/firebase-messaging.js');
// Change with your own Sender ID
firebase.initializeApp({
'messagingSenderId': '######'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
const notification = JSON.parse(payload.data.data);
const notificationTitle = notification.title;
const notificationOptions = {
body: notification.body,
icon: '/android-chrome-144x144.png',
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
if (workbox) {
// injected assets by Workbox CLI
workbox.precaching.precacheAndRoute([]);
// js/css files
workbox.routing.registerRoute(
/\.(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'static-resources',
})
);
// // images
workbox.routing.registerRoute(
// Cache image files.
/\.(?:png|jpg|jpeg|svg|gif)$/,
// Use the cache if it's available.
new workbox.strategies.CacheFirst({
// Use a custom cache name.
cacheName: 'image-cache',
plugins: [
new workbox.expiration.Plugin({
// Cache upto 50 images.
maxEntries: 50,
// Cache for a maximum of a week.
maxAgeSeconds: 7 * 24 * 60 * 60,
}),
new workbox.cacheableResponse.Plugin({
statuses: [200]
})
],
})
);
const networkFirstHandler = new workbox.strategies.NetworkFirst({
cacheName: 'dynamic',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 10
}),
new workbox.cacheableResponse.Plugin({
statuses: [200]
})
]
});
const FALLBACK_URL = workbox.precaching.getCacheKeyForURL('/offline.html'); // Your offline page, placed in /public dir, and will be cached
const matcher = ({ event }) => event.request.mode === 'navigate';
const handler = args =>
networkFirstHandler
.handle(args)
.then(response => response || caches.match(FALLBACK_URL))
.catch(() => caches.match(FALLBACK_URL));
workbox.routing.registerRoute(matcher, handler);
self.addEventListener('message', function (event) {
console.log('user request for update... (' + event.data.action + ')');
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});
}
// FILE PATH: /resources/js/sw-registry.js
// (optional) If you using firebase notification
import { messaging } from 'firebase';
let newWorker;
// Notify user if service worker file has changed.. and need to update
// in your layout blade file create this snippet for notification for example
//
// <div id="sw-snackbar">A new version of this app is available. Click <a id="reload">here</a> to update.</div>
//
function showUpdateBar() {
let snackbar = document.getElementById('sw-snackbar');
snackbar.className = 'show';
}
document.getElementById('reload').addEventListener('click', function(){
newWorker.postMessage({ action: 'skipWaiting' });
});
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/offline.js').then(reg => {
reg.addEventListener('updatefound', () => {
newWorker = reg.installing;
newWorker.addEventListener('statechange', () => {
switch (newWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
// Show update bar
showUpdateBar();
}
break;
}
});
});
}).catch((err) => {
console.log('ServiceWorker registration failed: ', err);
});
let refreshing;
navigator.serviceWorker.addEventListener('controllerchange', function () {
if (refreshing) return;
window.location.reload();
refreshing = true;
});
});
}
const mix = require('laravel-mix');
const WebpackShellPlugin = require('webpack-shell-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin;
mix.setPublicPath('public');
mix.sass('./resources/sass/app.scss', '/css/app.css');
mix.js('./resources/js/app.js', '/js/webapp.js')
.extract(['axios', 'vue', 'accounting', 'vuex', 'vuex-router-sync', 'vue-router', 'vue-lazyload', 'vue-i18n', 'vue-events', 'vee-validate'])
.webpackConfig({
output: {
chunkFilename: 'js/chunks/[name].js'
}
});
if (mix.inProduction()) {
mix.webpackConfig({
plugins: [new BundleAnalyzerPlugin()]
});
mix.version();
mix.disableNotifications();
}
/**
* Publishing the assets
*/
mix.webpackConfig({
plugins: [
new WebpackShellPlugin({
onBuildEnd: [
'npx workbox injectManifest workbox-config.js'
]
})
]
});
module.exports = {
// Path to be offline cache
'globDirectory': 'public/',
'globPatterns': [
'/**/*.{css,ico,ttf,woff,svg,png,jpg,php,js,xml,webmanifest,json,txt,gif,md,html,scss,eot,woff2,swf,otf}',
'offline.html',
'mix-manifest.json',
],
'swDest': 'public/offline.js',
'globIgnores': [],
'swSrc': 'resources/js/service-worker.js'
};
@seguis
Copy link

seguis commented Dec 31, 2019

Excellent friend, how long have you been programming?

@echr
Copy link
Author

echr commented Dec 31, 2019

Excellent friend, how long have you been programming?

Thanks! glad if it helpful. Around 5 years I guess and last 2 years mostly on Laravel & VueJS.

@seguis
Copy link

seguis commented Jan 2, 2020

Good bro, Sorry for the question, can you please guide me through the process, I want to create a PWA website with Push notifications, I thought of Laravel as backend and Vue as frontend, but a friend mentioned Nuxtjs, what do you think? Do you have a guide that can help me?

@DartedMonki
Copy link

Mas maaf mau tanya, saya sedang mengerjakan project Laravel + Vuejs namun masih bingung bagaimana cara mengaktifkan PWAnya. Saya jg tidak menggunakan firebase jadi kira2 apa saja yang harus diubah ya? Terima kasih!

@echr
Copy link
Author

echr commented Feb 29, 2020

Mas maaf mau tanya, saya sedang mengerjakan project Laravel + Vuejs namun masih bingung bagaimana cara mengaktifkan PWAnya. Saya jg tidak menggunakan firebase jadi kira2 apa saja yang harus diubah ya? Terima kasih!

Bisa diperjelas "aktifkan" seperti apa ya yg dimaksud?, service-worker.jsdan sw-registry.js ketika diload di app.js akan otomatis mengaktifkan service worker dan bisa digunakan untuk fitur-fitur PWA (offline, notification, dll). Jika tidak ingin menggunakan firebase notification cukup di hapus aja script import firebase-nya.

@GusApu
Copy link

GusApu commented Mar 2, 2020

halo gan ada tutorial gk ? cara untuk membuat notifikasi reminder menggunakan vue.js + laravel

@nkb-bd
Copy link

nkb-bd commented Feb 26, 2022

Nice , do you have any projects with laravel ,vue and firebase ?

@Tresor-Kasenda
Copy link

Nice , do you have any projects with laravel ,vue and firebase ?

how would you look in firebase ???

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment