From 7af4279f4579094cbe121cccb3c28357396e55d0 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Wed, 1 Jul 2026 07:32:55 +0200 Subject: [PATCH] ui: Remove PWA navigate fallback to prevent caching API endpoint requests (#25174) --- tools/ui/src/lib/constants/pwa.ts | 17 ++++++++++------- tools/ui/tests/e2e/pwa.e2e.ts | 5 ++++- tools/ui/tests/unit/pwa.spec.ts | 6 ++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/ui/src/lib/constants/pwa.ts b/tools/ui/src/lib/constants/pwa.ts index 80505fabd..b9171d4bb 100644 --- a/tools/ui/src/lib/constants/pwa.ts +++ b/tools/ui/src/lib/constants/pwa.ts @@ -288,9 +288,7 @@ export const API_CACHING_PATTERNS = { } as const; // SvelteKit PWA plugin options -export const PWA_KIT_OPTIONS = { - NAVIGATE_FALLBACK: './' -} as const; +export const PWA_KIT_OPTIONS = {} as const; export const APPLE_META_TAGS = { MOBILE_WEB_APP_CAPABLE: { name: 'apple-mobile-web-app-capable', content: 'yes' }, @@ -322,6 +320,14 @@ export const SVELTEKIT_PWA_OPTIONS: SvelteKitPWAOptions = { globIgnores: GLOB_IGNORES, maximumFileSizeToCacheInBytes: CACHE_SETTINGS.MAX_FILE_SIZE_BYTES, + // Prevent @vite-pwa/sveltekit from auto-adding a NavigationRoute by + // setting navigateFallback to empty string. This keeps the service + // worker from intercepting direct browser navigation to server API + // endpoints (e.g. /slots, /models, /v1/models) which should return + // JSON, not the SPA HTML shell. The server's own static-file fallback + // handles non-API navigation to index.html for the SPA router. + navigateFallback: '', + // Runtime caching for API calls - use NetworkFirst so APIs are always fresh runtimeCaching: [ { @@ -351,10 +357,7 @@ export const SVELTEKIT_PWA_OPTIONS: SvelteKitPWAOptions = { devOptions: { enabled: true, - suppressWarnings: true, - // Use PWA_KIT_OPTIONS.NAVIGATE_FALLBACK to match production SW behaviour - // (navigateFallback defaults to the configured base path, which is '/' for this SPA). - navigateFallback: PWA_KIT_OPTIONS.NAVIGATE_FALLBACK + suppressWarnings: true }, // SvelteKit-specific options diff --git a/tools/ui/tests/e2e/pwa.e2e.ts b/tools/ui/tests/e2e/pwa.e2e.ts index e21672239..c20eec276 100644 --- a/tools/ui/tests/e2e/pwa.e2e.ts +++ b/tools/ui/tests/e2e/pwa.e2e.ts @@ -43,7 +43,10 @@ test.describe('PWA Service Worker', () => { expect(swContent).toMatch(/"_app\/immutable\/assets\/bundle\.[a-zA-Z0-9_-]+\.css"/); expect(swContent).toMatch(/"manifest\.webmanifest"/); expect(swContent).toMatch(/"_app\/version\.json"/); - expect(swContent).toMatch(/NavigationRoute/); + // NavigationRoute is intentionally absent — server API endpoints + // (e.g. /slots, /models) must not be intercepted by the PWA and + // should return JSON directly from the server. + expect(swContent).not.toMatch(/NavigationRoute/); expect(swContent).toMatch(/api-cache/); }); diff --git a/tools/ui/tests/unit/pwa.spec.ts b/tools/ui/tests/unit/pwa.spec.ts index 0059e246c..17da27986 100644 --- a/tools/ui/tests/unit/pwa.spec.ts +++ b/tools/ui/tests/unit/pwa.spec.ts @@ -108,9 +108,11 @@ describe('PWA Build Output', () => { expect(swContent).toMatch(/"manifest\.webmanifest"/); }); - it('has navigation route registered', () => { + it('no navigation route — API endpoints bypass PWA', () => { expect(swContent).toBeTruthy(); - expect(swContent).toMatch(/NavigationRoute/); + // NavigationRoute is intentionally absent so direct browser + // navigation to server API endpoints returns JSON, not HTML. + expect(swContent).not.toMatch(/NavigationRoute/); }); it('has runtime caching for API routes', () => {