PWA fixed
added systemd service howto traefik nginix set_real_ip_from improved readme visuals fixed on mobile labels removed updated readme fixed visuals overlay for the hotkey disable screen lock clean up git precommit hooks clean up clean up update check for update feature added build-time information fixed date clean up added hook script fix fix fix hooks fixed webhook setup players stay in run all timers mode mqtt mqtt allways connected mqtt messages work capturing mqtt in edit player mqtt in Setup updated readme state of the mqtt Global Pass turn
This commit is contained in:
150
src/sw.js
Normal file
150
src/sw.js
Normal file
@@ -0,0 +1,150 @@
|
||||
// This global constant __APP_CACHE_VERSION__ will be replaced by Vite
|
||||
// during the build process due to the `define` config in vite.config.js.
|
||||
const CACHE_VERSION = typeof __APP_CACHE_VERSION__ !== 'undefined'
|
||||
? __APP_CACHE_VERSION__
|
||||
: 'nexus-timer-cache-fallback-dev-vManual'; // Fallback for dev or if define fails
|
||||
|
||||
const APP_SHELL_URLS = [
|
||||
// Note: '/' (index.html) is handled by NetworkFirst strategy, no need to precache explicitly here.
|
||||
'/manifest.json', // Will be served from public, copied to dist root
|
||||
'/favicon.ico', // Will be served from public, copied to dist root
|
||||
// Icons from public/icons, will be copied to dist/icons
|
||||
'/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',
|
||||
// Any other critical static assets from the public folder that should be part of the app shell
|
||||
];
|
||||
|
||||
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);
|
||||
})
|
||||
.then(() => {
|
||||
console.log(`[SW ${CACHE_VERSION}] Skip waiting on install.`);
|
||||
return 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(() => {
|
||||
console.log(`[SW ${CACHE_VERSION}] Clients claimed.`);
|
||||
return self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (request.method !== 'GET' || !url.protocol.startsWith('http')) {
|
||||
// console.log(`[SW ${CACHE_VERSION}] Ignoring non-GET or non-http(s) request: ${request.url}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Strategy 1: Network First for HTML (navigations or direct / request)
|
||||
if (request.mode === 'navigate' || (request.destination === 'document' || url.pathname === '/')) {
|
||||
// console.log(`[SW ${CACHE_VERSION}] NetworkFirst for: ${request.url}`);
|
||||
event.respondWith(
|
||||
fetch(request)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
const responseClone = response.clone();
|
||||
caches.open(CACHE_VERSION).then(cache => cache.put(request, responseClone));
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(async () => {
|
||||
// console.warn(`[SW ${CACHE_VERSION}] Network fetch failed for ${request.url}, trying cache.`);
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) return cachedResponse;
|
||||
// Fallback to root /index.html from cache if specific page not found offline
|
||||
const rootCache = await caches.match('/');
|
||||
if (rootCache) return rootCache;
|
||||
// console.error(`[SW ${CACHE_VERSION}] Network and cache miss for navigation: ${request.url}`);
|
||||
return new Response('Network error: You are offline and this page is not cached.', {
|
||||
status: 404,
|
||||
statusText: 'Not Found',
|
||||
headers: { 'Content-Type': 'text/html' } // Important for SPA offline fallback
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Strategy 2: Stale-While-Revalidate for assets (CSS, JS, images, fonts)
|
||||
if (request.destination === 'style' ||
|
||||
request.destination === 'script' ||
|
||||
request.destination === 'worker' ||
|
||||
request.destination === 'image' ||
|
||||
request.destination === 'font') {
|
||||
// console.log(`[SW ${CACHE_VERSION}] StaleWhileRevalidate for: ${request.url}`);
|
||||
event.respondWith(
|
||||
caches.open(CACHE_VERSION).then(cache => {
|
||||
return cache.match(request).then(cachedResponse => {
|
||||
const fetchPromise = fetch(request).then(networkResponse => {
|
||||
if (networkResponse.ok) {
|
||||
const responseToCache = networkResponse.clone();
|
||||
cache.put(request, responseToCache);
|
||||
} else {
|
||||
// console.warn(`[SW ${CACHE_VERSION}] StaleWhileRevalidate: Network fetch for ${request.url} failed with status ${networkResponse.status}`);
|
||||
}
|
||||
return networkResponse;
|
||||
}).catch(err => {
|
||||
// console.warn(`[SW ${CACHE_VERSION}] StaleWhileRevalidate: Network fetch error for ${request.url}:`, err);
|
||||
// If fetch fails, and we already served from cache, that's okay.
|
||||
// If cache also missed (i.e., cachedResponse was null), then this error will propagate.
|
||||
throw err;
|
||||
});
|
||||
return cachedResponse || fetchPromise;
|
||||
}).catch(err => {
|
||||
// This catch block handles errors from cache.match() or if fetchPromise was returned and rejected
|
||||
// console.error(`[SW ${CACHE_VERSION}] StaleWhileRevalidate: Error for ${request.url}. Trying network fallback.`, err);
|
||||
return fetch(request); // Final fallback to network if cache interactions fail
|
||||
});
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Strategy 3: Cache First for other types of requests (e.g., manifest.json if not in APP_SHELL_URLS)
|
||||
// console.log(`[SW ${CACHE_VERSION}] CacheFirst for: ${request.url}`);
|
||||
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;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('message', event => {
|
||||
if (event.data && event.data.action === 'skipWaiting') {
|
||||
console.log(`[SW ${CACHE_VERSION}] Received skipWaiting message, activating new SW.`);
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user