fix: scope PWA service workers to prevent cross-app interference
When multiple SPAs share the same origin (e.g., /sortir/ and /castle/ on demo.aiolabs.dev), their service workers conflict. Each app's workbox now scopes its navigateFallback with navigateFallbackAllowlist, and the main app excludes standalone paths via navigateFallbackDenylist. - Main app: denylist /sortir/ and /castle/ from its service worker - Sortir: allowlist only /sortir/ paths, fallback to activities.html - Castle: allowlist only /castle/ paths, fallback to castle.html - Icon paths use relative URLs (work with any base path) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
87f649f048
commit
7181b55d52
3 changed files with 21 additions and 10 deletions
|
|
@ -51,6 +51,11 @@ export default defineConfig(({ mode }) => ({
|
||||||
},
|
},
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
||||||
|
// Scope the service worker to only handle requests within this app's path
|
||||||
|
navigateFallback: 'activities.html',
|
||||||
|
navigateFallbackAllowlist: [
|
||||||
|
new RegExp(`^${(process.env.VITE_BASE_PATH || '/').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
includeAssets: [
|
includeAssets: [
|
||||||
'favicon.ico',
|
'favicon.ico',
|
||||||
|
|
@ -75,10 +80,10 @@ export default defineConfig(({ mode }) => ({
|
||||||
categories: ['social', 'entertainment', 'lifestyle'],
|
categories: ['social', 'entertainment', 'lifestyle'],
|
||||||
lang: 'fr',
|
lang: 'fr',
|
||||||
icons: [
|
icons: [
|
||||||
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
|
{ src: 'icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
|
||||||
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
|
{ src: 'icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
|
||||||
{ src: '/icon-maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
|
{ src: 'icon-maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
|
||||||
{ src: '/icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
|
{ src: 'icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ export default defineConfig(({ mode }) => ({
|
||||||
},
|
},
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
||||||
|
navigateFallback: 'castle.html',
|
||||||
|
navigateFallbackAllowlist: [
|
||||||
|
new RegExp(`^${(process.env.VITE_BASE_PATH || '/').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
includeAssets: [
|
includeAssets: [
|
||||||
'favicon.ico',
|
'favicon.ico',
|
||||||
|
|
@ -70,15 +74,15 @@ export default defineConfig(({ mode }) => ({
|
||||||
display: 'standalone',
|
display: 'standalone',
|
||||||
orientation: 'portrait-primary',
|
orientation: 'portrait-primary',
|
||||||
start_url: process.env.VITE_BASE_PATH || '/',
|
start_url: process.env.VITE_BASE_PATH || '/',
|
||||||
scope: '/',
|
scope: process.env.VITE_BASE_PATH || '/',
|
||||||
id: 'castle-accounting',
|
id: 'castle-accounting',
|
||||||
categories: ['finance', 'business', 'productivity'],
|
categories: ['finance', 'business', 'productivity'],
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
icons: [
|
icons: [
|
||||||
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
|
{ src: 'icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
|
||||||
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
|
{ src: 'icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
|
||||||
{ src: '/icon-maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
|
{ src: 'icon-maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
|
||||||
{ src: '/icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
|
{ src: 'icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ export default defineConfig(({ mode }) => ({
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: [
|
globPatterns: [
|
||||||
'**/*.{js,css,html,ico,png,svg}'
|
'**/*.{js,css,html,ico,png,svg}'
|
||||||
]
|
],
|
||||||
|
// Don't intercept standalone app paths — they have their own service workers
|
||||||
|
navigateFallbackDenylist: [/^\/sortir\//, /^\/castle\//],
|
||||||
},
|
},
|
||||||
includeAssets: [
|
includeAssets: [
|
||||||
'favicon.ico',
|
'favicon.ico',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue