SamDNX's picture
Propose alternative routes: another autoroute + a toll-free départementale way
cd2d39f
Raw
History Blame Contribute Delete
3.22 kB
/* Service worker: makes the map installable and usable offline.
* - App navigations are network-first (fresh prices when online), falling back
* to the last cached page when offline.
* - The app shell, icons and CDN libraries are cached so the app boots offline.
* - Map tiles are cached with a bounded LRU-ish cap for offline revisits.
*/
const VERSION = "v15";
const SHELL = "shell-" + VERSION;
const RUNTIME = "runtime-" + VERSION;
const TILES = "tiles-" + VERSION;
const TILE_LIMIT = 300;
const APP_SHELL = [
"/", "/index.html", "/styles.css", "/app.js", "/manifest.webmanifest",
"/icon-192.png", "/icon-512.png",
];
self.addEventListener("install", (event) => {
// Pre-cache the shell but don't auto-activate: the page shows an update prompt
// and tells us to skip waiting, so prices/assets never change under the user.
event.waitUntil(caches.open(SHELL).then((c) => c.addAll(APP_SHELL)));
});
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys.filter((k) => ![SHELL, RUNTIME, TILES].includes(k)).map((k) => caches.delete(k))
)
).then(() => self.clients.claim())
);
});
async function trimCache(name, max) {
const cache = await caches.open(name);
const keys = await cache.keys();
for (let i = 0; i < keys.length - max; i++) await cache.delete(keys[i]);
}
function cacheable(res) {
return res && (res.ok || res.type === "opaque");
}
self.addEventListener("fetch", (event) => {
const req = event.request;
if (req.method !== "GET") return;
const url = new URL(req.url);
// App navigation: fresh page online, cached shell offline.
if (req.mode === "navigate") {
event.respondWith(
fetch(req)
.then((res) => {
const copy = res.clone();
caches.open(SHELL).then((c) => c.put("/index.html", copy));
return res;
})
.catch(() => caches.match("/index.html").then((r) => r || caches.match("/")))
);
return;
}
// Map tiles: network-first, bounded cache for offline revisits.
if (url.hostname === "data.geopf.fr") {
event.respondWith(
fetch(req)
.then((res) => {
const copy = res.clone();
caches.open(TILES).then((c) => {
c.put(req, copy);
trimCache(TILES, TILE_LIMIT);
});
return res;
})
.catch(() => caches.match(req))
);
return;
}
// Same-origin assets + CDN libraries: cache-first, refresh in background.
if (url.origin === self.location.origin || url.hostname === "unpkg.com") {
event.respondWith(
caches.match(req).then((cached) => {
const network = fetch(req)
.then((res) => {
if (cacheable(res)) {
const copy = res.clone();
caches.open(RUNTIME).then((c) => c.put(req, copy));
}
return res;
})
.catch(() => cached);
return cached || network;
})
);
}
// Anything else (e.g. Nominatim geocoding) goes straight to the network.
});