-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathsw.js
More file actions
133 lines (114 loc) · 4.02 KB
/
Copy pathsw.js
File metadata and controls
133 lines (114 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* TravelMap Service Worker
* Caches map tiles for faster loading and offline support
*/
const CACHE_NAME = 'travelmap-tiles-v3'; // Incremented to force cache refresh after CARTO migration
const CACHE_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
// Tile domains to cache
const TILE_DOMAINS = [
'basemaps.cartocdn.com',
'a.basemaps.cartocdn.com',
'b.basemaps.cartocdn.com',
'c.basemaps.cartocdn.com',
'd.basemaps.cartocdn.com',
'tiles.openfreemap.org',
'api.maptiler.com',
'tile.openstreetmap.org'
];
// File extensions to cache from tile servers
const CACHEABLE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp', '.pbf', '.mvt'];
self.addEventListener('install', (event) => {
console.log('[SW] Installing TravelMap Service Worker');
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
console.log('[SW] Activating TravelMap Service Worker');
event.waitUntil(
Promise.all([
clients.claim(),
// Clean old caches
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(name => name.startsWith('travelmap-') && name !== CACHE_NAME)
.map(name => caches.delete(name))
);
})
])
);
});
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// Check if this is a tile request we should cache
const isTileRequest = TILE_DOMAINS.some(domain => url.hostname.includes(domain));
const isCacheableFile = CACHEABLE_EXTENSIONS.some(ext => url.pathname.endsWith(ext));
if (isTileRequest || isCacheableFile) {
event.respondWith(handleTileRequest(event.request));
}
});
async function handleTileRequest(request) {
const cache = await caches.open(CACHE_NAME);
// NETWORK FIRST strategy for tiles - this ensures fresh tiles are loaded
// Only fallback to cache if network fails
try {
const response = await fetch(request);
// Cache successful responses
if (response.status === 200) {
cache.put(request, response.clone());
}
return response;
} catch (error) {
// Network error - try cache
const cachedResponse = await cache.match(request);
if (cachedResponse) {
return cachedResponse;
}
// No cache either - return transparent fallback for tiles
return new Response('', {
status: 408,
statusText: 'Request Timeout'
});
}
}
async function refreshCache(request, cache) {
// This function is no longer used with network-first strategy
// Kept for backward compatibility if needed
try {
const response = await fetch(request);
if (response.status === 200) {
cache.put(request, response.clone());
}
} catch (error) {
// Silently fail - we have cached version
}
}
// Periodic cache cleanup
self.addEventListener('message', (event) => {
if (event.data === 'cleanup') {
cleanupCache();
} else if (event.data === 'clearCache') {
// Allow manual cache clearing
clearAllCaches();
}
});
async function clearAllCaches() {
const cacheNames = await caches.keys();
await Promise.all(
cacheNames
.filter(name => name.startsWith('travelmap-'))
.map(name => caches.delete(name))
);
console.log('[SW] All caches cleared');
}
async function cleanupCache() {
const cache = await caches.open(CACHE_NAME);
const requests = await cache.keys();
// Limit cache size to ~100MB worth of tiles (rough estimate)
const MAX_ENTRIES = 2000;
if (requests.length > MAX_ENTRIES) {
// Delete oldest entries (first in the list)
const toDelete = requests.slice(0, requests.length - MAX_ENTRIES);
await Promise.all(toDelete.map(req => cache.delete(req)));
console.log('[SW] Cleaned up', toDelete.length, 'cached tiles');
}
}