Skip to content

Instantly share code, notes, and snippets.

@m5lil
Forked from echr/app.js
Created July 18, 2020 20:35
Show Gist options
  • Save m5lil/a928ac03ab063eb73b8431a8f5818488 to your computer and use it in GitHub Desktop.
Save m5lil/a928ac03ab063eb73b8431a8f5818488 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');
const initializedFirebaseApp = firebase.initializeApp({
messagingSenderId: '#####'
});
let messaging = null;
if (firebase.messaging.isSupported()) {
messaging = initializedFirebaseApp.messaging();
messaging.usePublicVapidKey(
'#####'
);
messaging.onMessage((payload) => {
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: '/android-chrome-144x144.png',
};
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');
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');
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 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'
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment