added build-time information
This commit is contained in:
@@ -1,154 +0,0 @@
|
||||
const CACHE_VERSION = 'nexus-timer-cache-v10';
|
||||
const APP_SHELL_URLS = [
|
||||
// '/', // Let NetworkFirst handle '/'
|
||||
'/manifest.json',
|
||||
'/favicon.ico',
|
||||
'/icons/icon-192x192.png',
|
||||
'/icons/icon-512x512.png',
|
||||
'/icons/maskable-icon-192x192.png',
|
||||
'/icons/maskable-icon-512x512.png',
|
||||
'/icons/shortcut-setup-96x96.png',
|
||||
'/icons/shortcut-info-96x96.png',
|
||||
// Add Vite output paths? Usually hard due to hashing. Rely on dynamic caching.
|
||||
];
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
console.log(`[SW ${CACHE_VERSION}] Install`);
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_VERSION)
|
||||
.then(cache => {
|
||||
console.log(`[SW ${CACHE_VERSION}] Caching app shell essentials`);
|
||||
return cache.addAll(APP_SHELL_URLS); // Cache core static assets
|
||||
})
|
||||
.then(() => self.skipWaiting())
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
console.log(`[SW ${CACHE_VERSION}] Activate`);
|
||||
event.waitUntil(
|
||||
caches.keys().then(cacheNames => {
|
||||
return Promise.all(
|
||||
cacheNames.map(cacheName => {
|
||||
if (cacheName !== CACHE_VERSION) {
|
||||
console.log(`[SW ${CACHE_VERSION}] Deleting old cache: ${cacheName}`);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
}).then(() => self.clients.claim())
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
// Ignore non-GET requests & non-http protocols
|
||||
if (request.method !== 'GET' || !url.protocol.startsWith('http')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Strategy 1: Network First for HTML ---
|
||||
if (request.mode === 'navigate' || (request.destination === 'document' || url.pathname === '/')) {
|
||||
event.respondWith(
|
||||
fetch(request)
|
||||
.then(response => {
|
||||
// If fetch is successful, cache it and return it
|
||||
if (response.ok) {
|
||||
const responseClone = response.clone();
|
||||
caches.open(CACHE_VERSION).then(cache => cache.put(request, responseClone));
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(async () => {
|
||||
// If fetch fails, try cache
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
// If specific request not in cache, try root '/' as SPA fallback
|
||||
const rootCache = await caches.match('/');
|
||||
if (rootCache) {
|
||||
return rootCache;
|
||||
}
|
||||
// Optional: return a proper offline fallback page if available
|
||||
// return caches.match('/offline.html');
|
||||
// Or just let the browser show its offline error
|
||||
return new Response('Network error and no cache found.', { status: 404, statusText: 'Not Found' });
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Strategy 2: Stale-While-Revalidate for assets ---
|
||||
if (request.destination === 'style' ||
|
||||
request.destination === 'script' ||
|
||||
request.destination === 'worker' ||
|
||||
request.destination === 'image' ||
|
||||
request.destination === 'font') {
|
||||
event.respondWith(
|
||||
caches.open(CACHE_VERSION).then(cache => { // Open cache first
|
||||
return cache.match(request).then(cachedResponse => {
|
||||
// Fetch in parallel (don't wait for it here)
|
||||
const fetchPromise = fetch(request).then(networkResponse => {
|
||||
// Check if fetch was successful
|
||||
if (networkResponse.ok) {
|
||||
// Clone before caching
|
||||
const responseToCache = networkResponse.clone();
|
||||
// Update the cache with the network response
|
||||
cache.put(request, responseToCache);
|
||||
} else {
|
||||
console.warn(`[SW ${CACHE_VERSION}] Fetch for ${request.url} failed with status ${networkResponse.status}`);
|
||||
}
|
||||
// Return the original network response for the fetch promise resolution
|
||||
// This isn't directly used for the *initial* response unless cache misses.
|
||||
return networkResponse;
|
||||
}).catch(err => {
|
||||
console.warn(`[SW ${CACHE_VERSION}] Fetch error for ${request.url}:`, err);
|
||||
// If fetch fails, we just rely on the cache if it existed.
|
||||
// Re-throw error so if cache also missed, browser knows resource failed.
|
||||
throw err;
|
||||
});
|
||||
|
||||
// Return the cached response immediately if available.
|
||||
// If not cached, this strategy requires waiting for the fetch.
|
||||
// The common implementation returns cache THEN fetches, but if cache misses,
|
||||
// the user waits for the network. Let's return fetchPromise if no cache.
|
||||
return cachedResponse || fetchPromise;
|
||||
|
||||
}).catch(err => {
|
||||
// Error during cache match or subsequent fetch
|
||||
console.error(`[SW ${CACHE_VERSION}] Error handling fetch for ${request.url}:`, err);
|
||||
// Fallback to network just in case cache interaction failed? Or let browser handle.
|
||||
// Let's try network as a last resort if cache fails.
|
||||
return fetch(request);
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Strategy 3: Cache First for others ---
|
||||
// (e.g., manifest, potentially icons not pre-cached)
|
||||
event.respondWith(
|
||||
caches.match(request)
|
||||
.then(response => {
|
||||
return response || fetch(request).then(networkResponse => {
|
||||
if(networkResponse.ok) {
|
||||
const responseClone = networkResponse.clone();
|
||||
caches.open(CACHE_VERSION).then(cache => cache.put(request, responseClone));
|
||||
}
|
||||
return networkResponse;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Listener for skipWaiting message
|
||||
self.addEventListener('message', event => {
|
||||
if (event.data && event.data.action === 'skipWaiting') {
|
||||
console.log('[SW] Received skipWaiting message, activating new SW.');
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user