mirror of
https://github.com/gadgethd/ukmesh.git
synced 2026-09-16 12:02:35 +00:00
99 lines
3.0 KiB
JavaScript
99 lines
3.0 KiB
JavaScript
// Map tile service worker — caches CartoDB tiles so zooming/panning
|
|
// to previously visited areas loads instantly.
|
|
const TILE_CACHE_NAME = 'meshcore-tiles-v4';
|
|
const APP_CACHE_NAME = 'meshcore-app-v4';
|
|
const MAX_TILE_ENTRIES = 8000; // ~120 MB at ~15 KB per tile
|
|
const ACTIVE_CACHES = new Set([TILE_CACHE_NAME, APP_CACHE_NAME]);
|
|
|
|
const isTile = (url) =>
|
|
url.includes('basemaps.cartocdn.com');
|
|
|
|
const isAppAsset = (url) => {
|
|
const parsed = new URL(url);
|
|
return parsed.pathname.startsWith('/assets/');
|
|
};
|
|
|
|
self.addEventListener('install', () => self.skipWaiting());
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil((async () => {
|
|
const names = await caches.keys();
|
|
await Promise.all(names.map((name) => (ACTIVE_CACHES.has(name) ? Promise.resolve() : caches.delete(name))));
|
|
await self.clients.claim();
|
|
})());
|
|
});
|
|
|
|
// Cache tiles aggressively with stale-while-revalidate
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = event.request.url;
|
|
|
|
// Handle map tiles
|
|
if (isTile(url)) {
|
|
event.respondWith(
|
|
caches.open(TILE_CACHE_NAME).then(async (cache) => {
|
|
const cached = await cache.match(event.request);
|
|
|
|
const fetchPromise = fetch(event.request).then((response) => {
|
|
if (response.ok) {
|
|
cache.put(event.request, response.clone());
|
|
// Prune if needed
|
|
cache.keys().then((keys) => {
|
|
if (keys.length > MAX_TILE_ENTRIES) {
|
|
keys.slice(0, keys.length - MAX_TILE_ENTRIES).forEach((k) => cache.delete(k));
|
|
}
|
|
});
|
|
}
|
|
return response;
|
|
}).catch(() => cached);
|
|
|
|
// Return cached immediately, update in background
|
|
return cached || fetchPromise;
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Handle app assets - cache first, fallback to network
|
|
if (isAppAsset(url)) {
|
|
event.respondWith(
|
|
caches.open(APP_CACHE_NAME).then(async (cache) => {
|
|
const cached = await cache.match(event.request);
|
|
if (cached) return cached;
|
|
|
|
try {
|
|
const response = await fetch(event.request);
|
|
if (response.ok) {
|
|
cache.put(event.request, response.clone());
|
|
}
|
|
return response;
|
|
} catch {
|
|
// If offline and not cached, return offline page for navigation
|
|
if (event.request.mode === 'navigate') {
|
|
return cache.match('/');
|
|
}
|
|
throw new Error('offline');
|
|
}
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (event.request.mode === 'navigate') {
|
|
event.respondWith(
|
|
caches.open(APP_CACHE_NAME).then(async (cache) => {
|
|
try {
|
|
const response = await fetch(event.request);
|
|
if (response.ok) {
|
|
cache.put(event.request, response.clone());
|
|
}
|
|
return response;
|
|
} catch {
|
|
const cached = await cache.match(event.request);
|
|
if (cached) return cached;
|
|
const root = await cache.match('/');
|
|
return root || Response.error();
|
|
}
|
|
})
|
|
);
|
|
}
|
|
});
|