diff --git a/backend/main.py b/backend/main.py index c7316a4..989217e 100644 --- a/backend/main.py +++ b/backend/main.py @@ -408,7 +408,7 @@ async def serve_media(path: str, request: _Request): raise _HE(404, "Nicht gefunden.") return _media_response(filepath) -APP_VER = "980" # muss mit APP_VER in app.js übereinstimmen +APP_VER = "981" # muss mit APP_VER in app.js übereinstimmen @app.get("/.well-known/assetlinks.json") async def assetlinks(): diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 8c8ee55..f450de3 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '980'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '981'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; // Cache-Bust-Parameter nach Update-Reload sofort entfernen @@ -1140,6 +1140,19 @@ const App = (() => { window.App = App; // Worlds kann App.navigate() aufrufen // App starten +// Prioritäts-Seiten im Hintergrund vorladen (3s nach Start, damit Hauptinhalt nicht blockiert) +window.addEventListener('load', () => { + setTimeout(() => { + if (!('caches' in window)) return; + ['admin','erste-hilfe','diary','map','walks','routes','poison','lost'].forEach(page => { + const key = `Page_${page.replace(/-/g,'_')}`; + if (!window[key]) { + fetch(`/js/pages/${page}.js?v=${APP_VER}`).catch(() => {}); + } + }); + }, 3000); +}); + document.addEventListener('DOMContentLoaded', () => { App.init(); if (IS_STAGING) { diff --git a/backend/static/sw.js b/backend/static/sw.js index 76366b9..b78b525 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,16 +3,28 @@ Offline-Cache + Push Notifications + Tile-Cache ============================================================ */ -const CACHE_VERSION = 'by-v980'; +const CACHE_VERSION = 'by-v981'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache +// Prioritäts-Seiten: werden pre-gecacht + Stale-While-Revalidate +const PRIORITY_PAGES = [ + '/js/pages/admin.js', + '/js/pages/erste-hilfe.js', + '/js/pages/diary.js', + '/js/pages/map.js', + '/js/pages/walks.js', + '/js/pages/routes.js', + '/js/pages/poison.js', + '/js/pages/lost.js', +]; + // index.html wird NICHT pre-gecacht (immer Network-First) const STATIC_ASSETS = [ - '/css/design-system.css?v=700', - '/css/layout.css?v=700', - '/css/components.css?v=700', + '/css/design-system.css?v=980', + '/css/layout.css?v=980', + '/css/components.css?v=980', '/icons/phosphor.svg', '/js/api.js', '/js/ui.js', @@ -22,6 +34,7 @@ const STATIC_ASSETS = [ '/css/MarkerCluster.Default.css', '/manifest.json', '/icons/icon-192.png', + ...PRIORITY_PAGES, ]; // ---------------------------------------------------------- @@ -297,7 +310,21 @@ self.addEventListener('fetch', event => { return; } - // CSS, Core-JS + Seiten-Module: immer Network-First — damit iOS nie veraltete Versionen cached + // Prioritäts-Seiten: Stale-While-Revalidate — sofort aus Cache, im Hintergrund aktualisieren + if (PRIORITY_PAGES.includes(url.pathname)) { + event.respondWith( + caches.open(CACHE_STATIC).then(async cache => { + const cached = await cache.match(event.request, { ignoreSearch: true }); + const netFetch = fetch(event.request) + .then(res => { if (res.ok) cache.put(event.request, res.clone()); return res; }) + .catch(() => null); + return cached ?? (await netFetch) ?? new Response('', { status: 503 }); + }) + ); + return; + } + + // CSS, Core-JS + übrige Seiten-Module: Network-First — damit iOS nie veraltete Versionen cached if (url.pathname.startsWith('/css/') || url.pathname.startsWith('/js/pages/') || url.pathname.startsWith('/js/app.js') || url.pathname.startsWith('/js/ui.js') || url.pathname.startsWith('/js/api.js') || url.pathname.startsWith('/js/worlds.js')) { @@ -310,7 +337,7 @@ self.addEventListener('fetch', event => { } return response; }) - .catch(() => caches.match(event.request) + .catch(() => caches.match(event.request, { ignoreSearch: true }) .then(cached => cached || new Response('', { status: 503 }))) ); return;