Skip to content

Commit 5067720

Browse files
Refactor service worker for improved readability and error handling in caching logic
1 parent 144418f commit 5067720

1 file changed

Lines changed: 97 additions & 67 deletions

File tree

app/public/service-worker.js

Lines changed: 97 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,47 @@ const RUNTIME_MAX_ENTRIES = 100;
55
const RUNTIME_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
66

77
const CORE_ASSETS = [
8-
'/', '/offline', '/manifest.webmanifest',
8+
'/',
9+
'/offline',
10+
'/manifest.webmanifest',
911
'/fonts/AirbnbCereal_W_Bd.otf',
1012
'/fonts/Inter-VariableFont_opsz,wght.ttf',
1113
'/fonts/Montserrat-Regular.ttf',
12-
'/icons/icon-16x16.webp', '/icons/icon-32x32.webp',
13-
'/icons/icon-48x48.webp', '/icons/icon-64x64.webp',
14-
'/icons/icon-72x72.webp', '/icons/icon-76x76.webp',
15-
'/icons/icon-96x96.webp', '/icons/icon-114x114.webp',
16-
'/icons/icon-120x120.webp', '/icons/icon-128x128.webp',
17-
'/icons/icon-144x144.webp', '/icons/icon-152x152.webp',
18-
'/icons/icon-180x180.webp', '/icons/icon-192x192.webp',
19-
'/icons/icon-196x196.webp', '/icons/icon-228x228.webp',
20-
'/icons/icon-256x256.webp', '/icons/icon-384x384.webp',
21-
'/icons/icon-512x512.webp', '/apple-touch-icon.webp',
22-
'/icon.avif', '/icon.png', '/icon.svg', '/icon.webp',
23-
'/favicon.ico'
14+
'/icons/icon-16x16.webp',
15+
'/icons/icon-32x32.webp',
16+
'/icons/icon-48x48.webp',
17+
'/icons/icon-64x64.webp',
18+
'/icons/icon-72x72.webp',
19+
'/icons/icon-76x76.webp',
20+
'/icons/icon-96x96.webp',
21+
'/icons/icon-114x114.webp',
22+
'/icons/icon-120x120.webp',
23+
'/icons/icon-128x128.webp',
24+
'/icons/icon-144x144.webp',
25+
'/icons/icon-152x152.webp',
26+
'/icons/icon-180x180.webp',
27+
'/icons/icon-192x192.webp',
28+
'/icons/icon-196x196.webp',
29+
'/icons/icon-228x228.webp',
30+
'/icons/icon-256x256.webp',
31+
'/icons/icon-384x384.webp',
32+
'/icons/icon-512x512.webp',
33+
'/apple-touch-icon.webp',
34+
'/icon.avif',
35+
'/icon.png',
36+
'/icon.svg',
37+
'/icon.webp',
38+
'/favicon.ico',
2439
];
2540

2641
// -------------------- INSTALL --------------------
2742
self.addEventListener('install', (event) => {
2843
event.waitUntil(
29-
caches.open(PRECACHE)
30-
.then(cache => {
31-
const promises = CORE_ASSETS.map(asset =>
32-
cache.add(asset).catch(err => console.error(`Failed to cache ${asset}:`, err))
44+
caches
45+
.open(PRECACHE)
46+
.then((cache) => {
47+
const promises = CORE_ASSETS.map((asset) =>
48+
cache.add(asset).catch((err) => console.error(`Failed to cache ${asset}:`, err))
3349
);
3450
return Promise.all(promises);
3551
})
@@ -40,11 +56,13 @@ self.addEventListener('install', (event) => {
4056
// -------------------- ACTIVATE --------------------
4157
self.addEventListener('activate', (event) => {
4258
event.waitUntil(
43-
caches.keys()
44-
.then(keys => Promise.all(
45-
keys.filter(key => key !== PRECACHE && key !== RUNTIME)
46-
.map(key => caches.delete(key))
47-
))
59+
caches
60+
.keys()
61+
.then((keys) =>
62+
Promise.all(
63+
keys.filter((key) => key !== PRECACHE && key !== RUNTIME).map((key) => caches.delete(key))
64+
)
65+
)
4866
.then(() => self.clients.claim())
4967
);
5068
});
@@ -56,19 +74,19 @@ async function pruneRuntimeCache() {
5674
const now = Date.now();
5775

5876
let entries = await Promise.all(
59-
requests.map(async req => {
77+
requests.map(async (req) => {
6078
const res = await cache.match(req);
6179
const fetchedTime = res?.headers.get('SW-Fetched-Time');
6280
return { req, time: fetchedTime ? parseInt(fetchedTime) : 0 };
6381
})
6482
);
6583

6684
// Remove old entries
67-
const toDelete = entries.filter(entry => now - entry.time > RUNTIME_MAX_AGE).map(e => e.req);
68-
await Promise.all(toDelete.map(req => cache.delete(req)));
85+
const toDelete = entries.filter((entry) => now - entry.time > RUNTIME_MAX_AGE).map((e) => e.req);
86+
await Promise.all(toDelete.map((req) => cache.delete(req)));
6987

7088
// Remove excess entries
71-
entries = entries.filter(entry => now - entry.time <= RUNTIME_MAX_AGE);
89+
entries = entries.filter((entry) => now - entry.time <= RUNTIME_MAX_AGE);
7290
entries.sort((a, b) => a.time - b.time);
7391

7492
while (entries.length > RUNTIME_MAX_ENTRIES) {
@@ -86,58 +104,70 @@ self.addEventListener('fetch', (event) => {
86104

87105
// --- CORE ASSETS (cache-first) ---
88106
if (CORE_ASSETS.includes(url.pathname)) {
89-
event.respondWith((async () => {
90-
const cached = await caches.match(request);
91-
if (cached) {
92-
return cached;
93-
}
94-
try {
95-
const response = await fetch(request);
96-
if (response && response.status === 200) {
97-
const cache = await caches.open(PRECACHE);
98-
cache.put(request, response.clone());
107+
event.respondWith(
108+
(async () => {
109+
const cached = await caches.match(request);
110+
if (cached) {
111+
return cached;
99112
}
100-
return response;
101-
} catch {
102-
return await caches.match('/offline') || new Response('Service unavailable', { status: 503 });
103-
}
104-
})());
113+
try {
114+
const response = await fetch(request);
115+
if (response && response.status === 200) {
116+
const cache = await caches.open(PRECACHE);
117+
cache.put(request, response.clone());
118+
}
119+
return response;
120+
} catch {
121+
return (
122+
(await caches.match('/offline')) || new Response('Service unavailable', { status: 503 })
123+
);
124+
}
125+
})()
126+
);
105127
return;
106128
}
107129

108130
// --- NAVIGATION (network-first with offline fallback) ---
109131
if (request.mode === 'navigate') {
110-
event.respondWith((async () => {
111-
try {
112-
return await fetch(request);
113-
} catch (err) {
114-
console.error('Navigation fetch failed:', request.url, err);
115-
return await caches.match('/offline') || new Response('Offline', { status: 503 });
116-
}
117-
})());
132+
event.respondWith(
133+
(async () => {
134+
try {
135+
return await fetch(request);
136+
} catch (err) {
137+
console.error('Navigation fetch failed:', request.url, err);
138+
return (await caches.match('/offline')) || new Response('Offline', { status: 503 });
139+
}
140+
})()
141+
);
118142
return;
119143
}
120144

121145
// --- OTHER RUNTIME REQUESTS (network-first + runtime cache) ---
122-
event.respondWith((async () => {
123-
try {
124-
const response = await fetch(request);
125-
if (response && response.status === 200) {
126-
const cloned = response.clone();
127-
const headers = new Headers(cloned.headers);
128-
headers.set('SW-Fetched-Time', Date.now().toString());
129-
const modifiedResponse = new Response(await cloned.blob(), { headers });
130-
const cache = await caches.open(RUNTIME);
131-
await cache.put(request, modifiedResponse);
132-
await pruneRuntimeCache();
146+
event.respondWith(
147+
(async () => {
148+
try {
149+
const response = await fetch(request);
150+
if (response && response.status === 200) {
151+
const cloned = response.clone();
152+
const headers = new Headers(cloned.headers);
153+
headers.set('SW-Fetched-Time', Date.now().toString());
154+
const modifiedResponse = new Response(await cloned.blob(), { headers });
155+
const cache = await caches.open(RUNTIME);
156+
await cache.put(request, modifiedResponse);
157+
await pruneRuntimeCache();
158+
}
159+
return response;
160+
} catch (err) {
161+
console.error('Runtime fetch failed:', request.url, err);
162+
const cached = await caches.match(request);
163+
return (
164+
cached ||
165+
(await caches.match('/offline')) ||
166+
new Response('Service unavailable', { status: 503 })
167+
);
133168
}
134-
return response;
135-
} catch (err) {
136-
console.error('Runtime fetch failed:', request.url, err);
137-
const cached = await caches.match(request);
138-
return cached || await caches.match('/offline') || new Response('Service unavailable', { status: 503 });
139-
}
140-
})());
169+
})()
170+
);
141171
});
142172

143173
// -------------------- SKIP WAITING --------------------

0 commit comments

Comments
 (0)