The previous SW (pedscribe-v12) precached /js/app.js, /js/auth.js,
and /css/styles.css — all deleted in the previous commit. Without
this fix, every existing PWA install would 404 on the next SW
install attempt and serve stale cached vanilla pages forever.
Changes:
• CACHE_NAME bumped to pedscribe-v13 → activate event evicts the
v12 cache (and any earlier).
• SHELL_ASSETS narrowed to [/, /manifest.json]. Hashed Vite
assets are not precached because their filenames change on
every build — they're served fresh from the network with Vite's
immutable Cache-Control as backup.
• Fetch handler:
- /api/* → bypass SW (medical data must always be fresh).
- /app/assets/* → network-first, cache fallback for offline.
- everything else → cache-first with stale-while-revalidate.
• Promise.allSettled around cache.add() so a single missing
asset can't break the whole SW install.
Existing PWA users get the new shell on their next visit
(skipWaiting + clients.claim).
65 lines
2.4 KiB
JavaScript
65 lines
2.4 KiB
JavaScript
// ============================================================
|
|
// SERVICE WORKER — Cache the React shell + manifest.
|
|
// Network-first for API (medical data must always be fresh).
|
|
// Hashed Vite assets are NOT precached — they change every build,
|
|
// the browser HTTP cache plus immutable Cache-Control handles them.
|
|
// ============================================================
|
|
|
|
var CACHE_NAME = 'pedscribe-v13';
|
|
var SHELL_ASSETS = [
|
|
'/',
|
|
'/manifest.json',
|
|
];
|
|
|
|
// Install: precache shell. Errors swallowed so a missing single
|
|
// asset doesn't break SW install entirely.
|
|
self.addEventListener('install', function(event) {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then(function(cache) {
|
|
return Promise.allSettled(SHELL_ASSETS.map(function(url) {
|
|
return cache.add(url).catch(function() {});
|
|
}));
|
|
}).then(function() { return self.skipWaiting(); })
|
|
);
|
|
});
|
|
|
|
// Activate: clear old caches (deletes pedscribe-v12 and earlier).
|
|
self.addEventListener('activate', function(event) {
|
|
event.waitUntil(
|
|
caches.keys().then(function(names) {
|
|
return Promise.all(
|
|
names.filter(function(name) { return name !== CACHE_NAME; })
|
|
.map(function(name) { return caches.delete(name); })
|
|
);
|
|
}).then(function() { return self.clients.claim(); })
|
|
);
|
|
});
|
|
|
|
self.addEventListener('fetch', function(event) {
|
|
if (event.request.method !== 'GET') return;
|
|
var url = new URL(event.request.url);
|
|
// Same-origin only; skip cross-origin (CDN, fonts, etc.)
|
|
if (url.origin !== self.location.origin) return;
|
|
// API: network only — never cache medical data.
|
|
if (url.pathname.startsWith('/api/')) return;
|
|
// Hashed Vite assets: serve from network, fall back to cache if offline.
|
|
if (url.pathname.startsWith('/app/assets/')) {
|
|
event.respondWith(
|
|
fetch(event.request).catch(function() { return caches.match(event.request); })
|
|
);
|
|
return;
|
|
}
|
|
// SPA shell + everything else: cache-first with network update.
|
|
event.respondWith(
|
|
caches.match(event.request).then(function(cached) {
|
|
var fetchPromise = fetch(event.request).then(function(resp) {
|
|
if (resp && resp.status === 200) {
|
|
var copy = resp.clone();
|
|
caches.open(CACHE_NAME).then(function(cache) { cache.put(event.request, copy); });
|
|
}
|
|
return resp;
|
|
}).catch(function() { return cached; });
|
|
return cached || fetchPromise;
|
|
})
|
|
);
|
|
});
|