-
-
Save Tresor-Kasenda/c6b7ddb9c7ac4e559a1d13339f4b7c79 to your computer and use it in GitHub Desktop.
Simple Laravel + Vue + Laravel Mix + Firebase Notification (PWA, Offline)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// FILE PATH: /resources/js/app.js | |
require('./bootstrap'); | |
// Import Service Worker Registry | |
require('./extensions/sw-registry'); | |
import Vue from 'vue'; | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
} | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
}); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | |
] | |
}) | |
] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment