I have a laravel (inertia/vue) app (that used laravel-mix until recently) with a pwa feature that I built up using pwa builder and workbox.
Following the change from laravel-mix to vite in the laravel framework, I migrated to vite and its features work as expected, the js and css are injected into the head element of the entry page of the app, and vue pages work as expected, nothing is compiled and injected into the public folder in development, as was the case with laravel-mix/webpack.
I'm now having trouble getting the pwa feature to work as it did before. Since I'm no longer using webpack/laravel-mix, I replaced the webpack-workbox plugin I was using with this plugin: vite-plugin-pwa.
When I was using laravel-mix and webpack-workbox plugin, I simply point to my source service worker file in the webpack config file and use my desired workbox strategy to build up my final service worker file which then gets compiled and placed in my public folder along with other compiled css and js files.
With this vite plugin, my final service worker does not get compiled and placed in the public directory as such no service worker is discoverable for the app. I get a 404 error with the message: 'Failed to register a service worker for scope...', because no service worker file is available.
I suspect that I'm not configuring or using this plugin the correct way and would appreciate help with how to do this or otherwise resolve this.
This is my vite.config.js file:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.js',
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
compilerOptions: {
isCustomElement: tag => tag.startsWith('pwa-')
|| tag.startsWith('font-')
},
},
}),
VitePWA({
strategies: 'injectManifest',
swSrc: './public/sw.js',
swDest: './public/pwabuilder-sw.js',
devOptions: {
enabled: true,
type: 'module'
}
}),
],
});
This is my source service worker file in my public folder:
// This is the "Offline copy of assets" service worker
import {BackgroundSyncPlugin} from 'workbox-background-sync'
import {registerRoute} from 'workbox-routing'
import {StaleWhileRevalidate} from 'workbox-strategies'
import {ExpirationPlugin} from 'workbox-expiration'
const CACHE = "pwabuilder-offline"
const QUEUE_NAME = "bgSyncQueue"
self.__WB_DISABLE_DEV_LOGS = true
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting()
}
})
const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
})
const expPlugin = new ExpirationPlugin({
maxEntries: 5,
maxAgeSeconds: 1 * 24 * 60 * 60,
purgeOnQuotaError: true,
matchOptions: {
ignoreVary: true,
}
})
registerRoute(
new RegExp('/*'),
new StaleWhileRevalidate({
cacheName: CACHE,
plugins: [
bgSyncPlugin,
expPlugin
]
})
)
self.addEventListener('push', function (e) {
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}
if (e.data) {
const msg = e.data.json()
clients.matchAll().then(function(c) {
e.waitUntil(self.registration.showNotification('SmartWealth Push Notification', {
body: msg.notification.body,
icon: msg.notification.icon,
actions: msg.notification.actions,
deep_link: msg.notification.deep_link
}))
})
}
})
UPDATE This is my current SW using workbox CDN:
// This is the "Offline copy of assets" service worker
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.4/workbox-sw.js')
const {BackgroundSyncPlugin} = workbox.backgroundSync
const {registerRoute} = workbox.routing
const {StaleWhileRevalidate} = workbox.strategies
const {ExpirationPlugin} = workbox.expiration
const CACHE = "offlineAssets"
const QUEUE_NAME = "bgSyncQueue"
self.__WB_DISABLE_DEV_LOGS = true
self.addEventListener('install', () => self.skipWaiting())
self.addEventListener('activate', () => self.clients.claim())
const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
})
const expPlugin = new ExpirationPlugin({
maxEntries: 5,
maxAgeSeconds: 1 * 24 * 60 * 60,
purgeOnQuotaError: true,
matchOptions: {
ignoreVary: true,
}
})
registerRoute(
new RegExp('/*'),
new StaleWhileRevalidate({
cacheName: CACHE,
plugins: [
bgSyncPlugin,
expPlugin
]
})
)
self.addEventListener('push', (e) => {
if (!(self.Notification && self.Notification.permission === 'granted')) return
if (!e.data) return
const msg = e.data.json()
e.waitUntil(clients.matchAll()
.then((clients) => {
// console.log(msg, clients)
clients.forEach((client) => {
const url = client.url
const id = url.slice(url.lastIndexOf('/') + 1)
if (!client.url.includes(`chat/messages/${id}`)) { //send only if not on chat url for particular sender.
self.registration.showNotification('SmartWealth Push Notification', {
body: msg.notification.body,
icon: msg.notification.icon,
actions: msg.notification.actions,
deep_link: msg.notification.deep_link
})
}
})
}))
})
self.addEventListener('notificationclick', () => {}) //to do
I no longer require vite to inject my SW.
swSrc: './public/sw.sj'
– Stonefish