fix: optimize bunker loading and add progress feedback
This commit is contained in:
51
public/sw.js
51
public/sw.js
@@ -1,4 +1,4 @@
|
||||
const CACHE_NAME = 'whisky-vault-v7-bunker'; // Neue Version für stabilen Bunker + SWR
|
||||
const CACHE_NAME = 'whisky-vault-v8-bunker'; // Optimierter Bunker v8
|
||||
|
||||
// CONFIG: Kern-Seiten und Assets für den Bunker (sofortiges Pre-Caching)
|
||||
const CORE_PAGES = [
|
||||
@@ -6,13 +6,13 @@ const CORE_PAGES = [
|
||||
];
|
||||
|
||||
const STATIC_ASSETS = [
|
||||
'/manifest.webmanifest', // Korrigierter Pfad für Next.js
|
||||
'/manifest.webmanifest',
|
||||
'/icon-192.png',
|
||||
'/icon-512.png',
|
||||
'/favicon.ico',
|
||||
];
|
||||
|
||||
// Helper: Fetch mit Timeout und AbortController (sauberer Abbruch)
|
||||
// Helper: Fetch mit Timeout und Sauberen Abort
|
||||
async function fetchWithTimeout(request, timeoutMs = 3000) {
|
||||
const controller = new AbortController();
|
||||
const id = setTimeout(() => controller.abort(), timeoutMs);
|
||||
@@ -26,36 +26,47 @@ async function fetchWithTimeout(request, timeoutMs = 3000) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Broadcast an alle Clients
|
||||
async function broadcast(message) {
|
||||
const clients = await self.clients.matchAll();
|
||||
clients.forEach(client => client.postMessage(message));
|
||||
}
|
||||
|
||||
// Install: Lade alles Wichtige einzeln in den Bunker
|
||||
self.addEventListener('install', (event) => {
|
||||
self.skipWaiting();
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then(async (cache) => {
|
||||
console.log('🏗️ PWA: Building bunker v7...');
|
||||
console.log('🏗️ PWA: Building bunker v8...');
|
||||
const total = CORE_PAGES.length + STATIC_ASSETS.length;
|
||||
let loaded = 0;
|
||||
|
||||
const promises = [...CORE_PAGES, ...STATIC_ASSETS].map(async (url) => {
|
||||
try {
|
||||
const res = await fetch(url);
|
||||
// Im Dev-Mode kann / lange dauern (Kompilierung). 10s Timeout.
|
||||
const res = await fetchWithTimeout(url, 10000);
|
||||
if (!res.ok) throw new Error(`Status ${res.status}`);
|
||||
return cache.put(url, res);
|
||||
await cache.put(url, res);
|
||||
} catch (error) {
|
||||
console.error(`⚠️ PWA: Pre-cache failed for ${url}:`, error);
|
||||
} finally {
|
||||
loaded++;
|
||||
broadcast({
|
||||
type: 'PRECACHE_PROGRESS',
|
||||
progress: Math.round((loaded / total) * 100)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
console.log('✅ PWA: Bunker build finished');
|
||||
|
||||
// Signal to clients that pre-caching is complete
|
||||
// Signal an Clients: Bunker ist bereit
|
||||
broadcast({ type: 'PRECACHE_COMPLETE', version: CACHE_NAME });
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Helper: Broadcast to all clients
|
||||
async function broadcast(message) {
|
||||
const clients = await self.clients.matchAll();
|
||||
clients.forEach(client => client.postMessage(message));
|
||||
}
|
||||
|
||||
// Activate: Alte Bunker räumen
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
@@ -114,7 +125,6 @@ self.addEventListener('fetch', (event) => {
|
||||
}
|
||||
|
||||
// 2. ASSETS & NAVIGATION: Stale-While-Revalidate (Der "Echte" Bunker Mode)
|
||||
// Wir liefern SOFORT aus dem Cache, fragen aber im Hintergrund das Netzwerk.
|
||||
const isNavigation = event.request.mode === 'navigate';
|
||||
const isAsset = event.request.destination === 'style' ||
|
||||
event.request.destination === 'script' ||
|
||||
@@ -126,7 +136,7 @@ self.addEventListener('fetch', (event) => {
|
||||
if (isNavigation || isAsset) {
|
||||
event.respondWith(
|
||||
caches.match(event.request).then(async (cachedResponse) => {
|
||||
// Hintergrund-Update vorbereiten
|
||||
// Hintergrund-Update
|
||||
const fetchPromise = fetchWithTimeout(event.request, 5000)
|
||||
.then(async (networkResponse) => {
|
||||
if (networkResponse && networkResponse.status === 200) {
|
||||
@@ -135,21 +145,14 @@ self.addEventListener('fetch', (event) => {
|
||||
}
|
||||
return networkResponse;
|
||||
})
|
||||
.catch(() => { /* Fail silently in background */ });
|
||||
.catch(() => { /* Silent in background */ });
|
||||
|
||||
// Navigation Fallback Logik
|
||||
if (isNavigation) {
|
||||
if (cachedResponse) return cachedResponse;
|
||||
|
||||
// Root Fallback für Deep Links (App Shell)
|
||||
const shell = await caches.match('/');
|
||||
if (shell) {
|
||||
console.log('[SW] Route not cached, using Root App Shell fallback');
|
||||
return shell;
|
||||
}
|
||||
if (shell) return shell;
|
||||
}
|
||||
|
||||
// Assets: Cache oder Netzwerk
|
||||
return cachedResponse || fetchPromise || fetch(event.request);
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user