Skip to content

Commit 8e850b1

Browse files
committed
better caching
1 parent 1470702 commit 8e850b1

1 file changed

Lines changed: 103 additions & 35 deletions

File tree

static/sw.js

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@ self.addEventListener('activate', event => {
5252
);
5353
});
5454

55+
// Helper function to identify large game files
56+
function isLargeGameFile(url) {
57+
// Add patterns for your large game files
58+
const gameFilePatterns = [
59+
/\.data$/, // Unity WebGL data files
60+
/\.wasm$/, // WebAssembly files
61+
/\.bundle$/, // Asset bundles
62+
/\.unity3d$/, // Unity asset files
63+
/\.pak$/, // Package files
64+
/\.bin$/, // Binary files
65+
// Add your specific large file extensions here
66+
];
67+
68+
return gameFilePatterns.some(pattern => pattern.test(url.pathname)) ||
69+
url.pathname.includes('assets/') ||
70+
url.pathname.includes('gamedata/');
71+
}
72+
5573
// Helper function to determine if a request should be cached
5674
function isCacheableRequest(request) {
5775
const url = new URL(request.url);
@@ -84,7 +102,9 @@ function isCacheableRequest(request) {
84102
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg',
85103
'.woff', '.woff2', '.ttf', '.otf',
86104
'.mp3', '.ogg', '.wav',
87-
'.mp4', '.webm'
105+
'.mp4', '.webm',
106+
// Game file extensions
107+
'.data', '.wasm', '.bundle', '.unity3d', '.pak', '.bin'
88108
];
89109

90110
if (extensions.some(ext => url.pathname.endsWith(ext))) {
@@ -94,6 +114,15 @@ function isCacheableRequest(request) {
94114
return false;
95115
}
96116

117+
// Helper function to check if response is valid for caching
118+
function isValidResponse(response) {
119+
return response &&
120+
response.ok &&
121+
response.status >= 200 &&
122+
response.status < 300 &&
123+
response.status !== 209; // Explicitly exclude 209 responses
124+
}
125+
97126
// Network-first strategy with fallback to cache
98127
async function networkFirstStrategy(request) {
99128
try {
@@ -109,15 +138,25 @@ async function networkFirstStrategy(request) {
109138
// Try network first
110139
const networkResponse = await fetch(request, fetchOptions);
111140

112-
// If successful, clone and cache
113-
if (networkResponse.ok) {
141+
// If successful and valid for caching, clone and cache
142+
if (isValidResponse(networkResponse)) {
114143
const cache = await caches.open(CACHE_NAME);
115144
cache.put(request, networkResponse.clone());
116145
return networkResponse;
117146
}
118147

119-
// If network fails with an error status, try cache
120-
throw new Error('Network response was not ok');
148+
// If network response is not valid for caching, try cache
149+
if (networkResponse.status === 209) {
150+
console.log('Received 209 response, falling back to cache for:', request.url);
151+
}
152+
153+
const cachedResponse = await caches.match(request);
154+
if (cachedResponse) {
155+
return cachedResponse;
156+
}
157+
158+
// Return the network response even if not cacheable
159+
return networkResponse;
121160
} catch (error) {
122161
// Fall back to cache
123162
const cachedResponse = await caches.match(request);
@@ -154,8 +193,8 @@ async function cacheFirstStrategy(request) {
154193

155194
const networkResponse = await fetch(request, fetchOptions);
156195

157-
// Cache the network response for future
158-
if (networkResponse.ok) {
196+
// Cache the network response for future if it's valid
197+
if (isValidResponse(networkResponse)) {
159198
const cache = await caches.open(CACHE_NAME);
160199
cache.put(request, networkResponse.clone());
161200
}
@@ -181,7 +220,7 @@ async function staleWhileRevalidateStrategy(request) {
181220
}
182221

183222
const fetchPromise = fetch(request, fetchOptions).then(networkResponse => {
184-
if (networkResponse.ok) {
223+
if (isValidResponse(networkResponse)) {
185224
const cache = caches.open(CACHE_NAME).then(cache => {
186225
cache.put(request, networkResponse.clone());
187226
return networkResponse;
@@ -207,7 +246,8 @@ async function timeAwareCacheFirstStrategy(request) {
207246
if (cachedResponse && !isStale) {
208247
return cachedResponse;
209248
}
210-
console.log(request.url, isStale)
249+
250+
console.log('Cache miss or stale for:', request.url, { isStale, hasCached: !!cachedResponse });
211251

212252
// Otherwise, get from network (either no cache or stale cache)
213253
try {
@@ -219,17 +259,20 @@ async function timeAwareCacheFirstStrategy(request) {
219259

220260
const networkResponse = await fetch(request, fetchOptions);
221261

222-
// Cache the network response for future
223-
if (networkResponse.ok) {
262+
// Cache the network response for future if it's valid
263+
if (isValidResponse(networkResponse)) {
224264
const cache = await caches.open(CACHE_NAME);
225265
await cache.put(request, networkResponse.clone());
226266
await updateCacheTimestamp(request.url);
267+
} else if (networkResponse.status === 209) {
268+
console.log('Received 209 response, not caching:', request.url);
227269
}
228270

229271
return networkResponse;
230272
} catch (error) {
231273
// If network fails and we have a cached version (even if stale), return it
232274
if (cachedResponse) {
275+
console.log('Network failed, returning stale cache for:', request.url);
233276
return cachedResponse;
234277
}
235278

@@ -249,35 +292,49 @@ async function saveMetadataStore(metadata) {
249292

250293
// Helper function to update timestamp for a cached file
251294
async function updateCacheTimestamp(url) {
252-
const metadata = await getMetadataStore();
253-
metadata[url] = Date.now();
254-
await saveMetadataStore(metadata);
295+
try {
296+
const metadata = await getMetadataStore();
297+
metadata[url] = Date.now();
298+
await saveMetadataStore(metadata);
299+
} catch (error) {
300+
console.error('Failed to update cache timestamp:', error);
301+
}
255302
}
256303

257304
async function isFileStale(url) {
258-
const metadata = await getMetadataStore();
259-
const timestamp = metadata[url];
260-
261-
if (!timestamp) {
262-
console.log("No timestamp for", url);
263-
return true; // No timestamp means we should revalidate
305+
try {
306+
const metadata = await getMetadataStore();
307+
const timestamp = metadata[url];
308+
309+
if (!timestamp) {
310+
console.log("No timestamp for", url);
311+
return true; // No timestamp means we should revalidate
312+
}
313+
314+
const now = Date.now();
315+
const age = now - timestamp;
316+
const maxAgeMs = MAX_AGE_DAYS * 24 * 60 * 60 * 1000; // Convert days to milliseconds
317+
return age > maxAgeMs;
318+
} catch (error) {
319+
console.error('Error checking if file is stale:', error);
320+
return true; // Assume stale on error
264321
}
265-
266-
const now = Date.now();
267-
const age = now - timestamp;
268-
const maxAgeMs = MAX_AGE_DAYS * 24 * 60 * 60 * 1000; // Convert days to milliseconds
269-
return age > maxAgeMs;
270322
}
271323

272324
// Helper function to get the cache metadata store
273325
async function getMetadataStore() {
274-
const cache = await caches.open(CACHE_NAME);
275-
const metadataResponse = await cache.match(CACHE_METADATA_KEY);
276-
277-
if (metadataResponse) {
278-
return metadataResponse.json();
279-
} else {
280-
// Initialize with empty metadata if none exists
326+
try {
327+
const cache = await caches.open(CACHE_NAME);
328+
const metadataResponse = await cache.match(CACHE_METADATA_KEY);
329+
330+
if (metadataResponse) {
331+
return await metadataResponse.json();
332+
} else {
333+
// Initialize with empty metadata if none exists
334+
return {};
335+
}
336+
} catch (error) {
337+
console.error('Error getting metadata store:', error);
281338
return {};
282339
}
283340
}
@@ -299,11 +356,12 @@ self.addEventListener('fetch', event => {
299356
if (isImage && isExternalDomain) {
300357
event.respondWith(timeAwareCacheFirstStrategy(request));
301358
}
302-
// For game assets, use cache-first
303-
else if (request.url.includes('game_')) {
359+
// For game assets, use cache-first (these are your large files)
360+
else if (request.url.includes('game_') || isLargeGameFile(url)) {
361+
console.log('Service worker caching game asset:', request.url);
304362
event.respondWith(cacheFirstStrategy(request));
305363
}
306-
// For HTML and JSON files, use network-first to get latest versions
364+
// For HTML, JSON, TXT and JS files, use network-first to get latest versions
307365
else if (request.url.endsWith('.html') || request.url.endsWith('.json') || request.url.endsWith('.txt') || request.url.endsWith('.js')) {
308366
event.respondWith(networkFirstStrategy(request));
309367
}
@@ -323,4 +381,14 @@ self.addEventListener('message', event => {
323381
event.ports[0].postMessage({ status: 'Cache cleared' });
324382
});
325383
}
384+
385+
// Handle force refresh for specific URLs
386+
if (event.data && event.data.action === 'FORCE_REFRESH') {
387+
const url = event.data.url;
388+
caches.open(CACHE_NAME).then(cache => {
389+
cache.delete(url).then(() => {
390+
event.ports[0].postMessage({ status: `Cache cleared for ${url}` });
391+
});
392+
});
393+
}
326394
});

0 commit comments

Comments
 (0)