Browse Source

Fix caching issues - always fetch fresh content from server

Service Worker changes:
- Bump version to v1.0.1 to invalidate old caches
- Use network-first strategy for all API calls
- Use network-first strategy for HTML files
- Only use cache-first for static assets (CSS, JS libs, images)

Server changes:
- Serve service-worker.js with no-cache headers
- Serve HTML files with no-cache headers

Client changes:
- Detect service worker updates and auto-reload page
- Check for updates on every page load

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
master
HikeMap User 1 month ago
parent
commit
279f4bcfb8
  1. 23
      index.html
  2. 14
      server.js
  3. 48
      service-worker.js

23
index.html

@ -9850,6 +9850,23 @@
.then(registration => {
console.log('Service Worker registered:', registration.scope);
// Check for updates on every page load
registration.update();
// Handle service worker updates
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
console.log('New service worker installing...');
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// New version available - skip waiting and reload
console.log('New version available, activating...');
newWorker.postMessage({ type: 'SKIP_WAITING' });
}
});
});
// Check for updates periodically
setInterval(() => {
registration.update();
@ -9860,6 +9877,12 @@
});
});
// Reload page when new service worker takes control
navigator.serviceWorker.addEventListener('controllerchange', () => {
console.log('New service worker activated, reloading...');
window.location.reload();
});
// Listen for app install prompt
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {

14
server.js

@ -64,6 +64,20 @@ app.use('/api', (req, res, next) => {
next();
});
// Serve service-worker.js with no-cache (critical for updates)
app.get('/service-worker.js', (req, res) => {
res.set('Cache-Control', 'no-store, no-cache, must-revalidate');
res.set('Pragma', 'no-cache');
res.sendFile(path.join(__dirname, 'service-worker.js'));
});
// Serve HTML files with no-cache to ensure fresh content
app.get(['/', '/index.html', '/admin.html'], (req, res, next) => {
res.set('Cache-Control', 'no-store, no-cache, must-revalidate');
res.set('Pragma', 'no-cache');
next();
});
// Serve static files - prioritize data directory for default.kml
app.get('/default.kml', async (req, res) => {
try {

48
service-worker.js

@ -1,5 +1,6 @@
// HikeMap Service Worker
const CACHE_NAME = 'hikemap-v1.0.0';
// Increment version to force cache refresh
const CACHE_NAME = 'hikemap-v1.0.1';
const urlsToCache = [
'/',
'/index.html',
@ -78,13 +79,51 @@ self.addEventListener('fetch', event => {
return;
}
// Handle API calls with network-first strategy
// Handle ALL API calls with network-first strategy
if (url.pathname.startsWith('/api/')) {
event.respondWith(
fetch(event.request)
.then(response => {
return response;
})
.catch(() => {
// Fall back to cache for API calls if offline
return caches.match(event.request);
})
);
return;
}
// Handle HTML files with network-first strategy (always get fresh version)
if (event.request.destination === 'document' ||
url.pathname === '/' ||
url.pathname.endsWith('.html')) {
event.respondWith(
fetch(event.request)
.then(response => {
// Cache the fresh version
if (response.status === 200) {
const responseToCache = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
}
return response;
})
.catch(() => {
// Fall back to cache only if network fails
return caches.match(event.request);
})
);
return;
}
// Handle geocache/KML data with network-first
if (url.pathname.includes('/save-kml') ||
url.pathname.includes('/geocaches')) {
event.respondWith(
fetch(event.request)
.then(response => {
// Cache successful API responses
if (response.status === 200) {
const responseToCache = response.clone();
caches.open(GEOCACHE_CACHE).then(cache => {
@ -94,14 +133,13 @@ self.addEventListener('fetch', event => {
return response;
})
.catch(() => {
// Fall back to cache for API calls
return caches.match(event.request);
})
);
return;
}
// Default strategy: cache-first for assets
// Default strategy: cache-first for static assets (CSS, JS libraries, images)
event.respondWith(
caches.match(event.request)
.then(response => {

Loading…
Cancel
Save