|
1 | | -const CACHE_NAME = 'pushy-site-v1'; |
| 1 | +const CACHE_NAME = 'pushy-site-v2'; |
2 | 2 | const PRECACHE_URLS = ['/', '/manifest.webmanifest', '/images/logo.svg']; |
3 | 3 |
|
4 | | -self.addEventListener('install', (event) => { |
5 | | - event.waitUntil( |
6 | | - caches |
7 | | - .open(CACHE_NAME) |
8 | | - .then((cache) => cache.addAll(PRECACHE_URLS)) |
9 | | - .then(() => self.skipWaiting()), |
10 | | - ); |
11 | | -}); |
| 4 | +// Never cache on dev origins: the dev server's JS URLs are not content-hashed, |
| 5 | +// so a cache-first SW pins a stale bundle whose HMR hash no longer exists on |
| 6 | +// the server, causing an infinite 404 → reload loop. This branch self-destructs |
| 7 | +// (clears caches + unregisters) so previously poisoned browsers heal on the |
| 8 | +// next service-worker update check. |
| 9 | +const DEV_HOSTNAMES = ['localhost', '127.0.0.1', '::1', '[::1]']; |
12 | 10 |
|
13 | | -self.addEventListener('activate', (event) => { |
14 | | - event.waitUntil( |
15 | | - caches |
16 | | - .keys() |
17 | | - .then((keys) => |
18 | | - Promise.all( |
19 | | - keys |
20 | | - .filter((key) => key !== CACHE_NAME) |
21 | | - .map((key) => caches.delete(key)), |
22 | | - ), |
23 | | - ) |
24 | | - .then(() => self.clients.claim()), |
25 | | - ); |
26 | | -}); |
| 11 | +if (DEV_HOSTNAMES.includes(self.location.hostname)) { |
| 12 | + self.addEventListener('install', () => self.skipWaiting()); |
| 13 | + self.addEventListener('activate', (event) => { |
| 14 | + event.waitUntil( |
| 15 | + caches |
| 16 | + .keys() |
| 17 | + .then((keys) => Promise.all(keys.map((key) => caches.delete(key)))) |
| 18 | + .then(() => self.registration.unregister()) |
| 19 | + .then(() => self.clients.matchAll({ type: 'window' })) |
| 20 | + .then((clients) => { |
| 21 | + for (const client of clients) { |
| 22 | + client.navigate(client.url).catch(() => {}); |
| 23 | + } |
| 24 | + }), |
| 25 | + ); |
| 26 | + }); |
| 27 | +} else { |
| 28 | + self.addEventListener('install', (event) => { |
| 29 | + event.waitUntil( |
| 30 | + caches |
| 31 | + .open(CACHE_NAME) |
| 32 | + .then((cache) => cache.addAll(PRECACHE_URLS)) |
| 33 | + .then(() => self.skipWaiting()), |
| 34 | + ); |
| 35 | + }); |
27 | 36 |
|
28 | | -self.addEventListener('fetch', (event) => { |
29 | | - const { request } = event; |
| 37 | + self.addEventListener('activate', (event) => { |
| 38 | + event.waitUntil( |
| 39 | + caches |
| 40 | + .keys() |
| 41 | + .then((keys) => |
| 42 | + Promise.all( |
| 43 | + keys |
| 44 | + .filter((key) => key !== CACHE_NAME) |
| 45 | + .map((key) => caches.delete(key)), |
| 46 | + ), |
| 47 | + ) |
| 48 | + .then(() => self.clients.claim()), |
| 49 | + ); |
| 50 | + }); |
30 | 51 |
|
31 | | - if (request.method !== 'GET') { |
32 | | - return; |
33 | | - } |
| 52 | + self.addEventListener('fetch', (event) => { |
| 53 | + const { request } = event; |
34 | 54 |
|
35 | | - const url = new URL(request.url); |
36 | | - if (url.origin !== self.location.origin) { |
37 | | - return; |
38 | | - } |
| 55 | + if (request.method !== 'GET') { |
| 56 | + return; |
| 57 | + } |
39 | 58 |
|
40 | | - if (request.mode === 'navigate') { |
41 | | - event.respondWith( |
42 | | - fetch(request) |
43 | | - .then((response) => { |
44 | | - const copy = response.clone(); |
45 | | - caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); |
46 | | - return response; |
47 | | - }) |
48 | | - .catch(() => caches.match(request).then((cached) => cached || caches.match('/'))), |
49 | | - ); |
50 | | - return; |
51 | | - } |
| 59 | + const url = new URL(request.url); |
| 60 | + if (url.origin !== self.location.origin) { |
| 61 | + return; |
| 62 | + } |
52 | 63 |
|
53 | | - event.respondWith( |
54 | | - caches.match(request).then((cached) => { |
55 | | - if (cached) { |
56 | | - return cached; |
57 | | - } |
| 64 | + if (request.mode === 'navigate') { |
| 65 | + event.respondWith( |
| 66 | + fetch(request) |
| 67 | + .then((response) => { |
| 68 | + const copy = response.clone(); |
| 69 | + caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); |
| 70 | + return response; |
| 71 | + }) |
| 72 | + .catch(() => |
| 73 | + caches.match(request).then((cached) => cached || caches.match('/')), |
| 74 | + ), |
| 75 | + ); |
| 76 | + return; |
| 77 | + } |
58 | 78 |
|
59 | | - return fetch(request).then((response) => { |
60 | | - if (response.ok) { |
61 | | - const copy = response.clone(); |
62 | | - caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); |
| 79 | + event.respondWith( |
| 80 | + caches.match(request).then((cached) => { |
| 81 | + if (cached) { |
| 82 | + return cached; |
63 | 83 | } |
64 | | - return response; |
65 | | - }); |
66 | | - }), |
67 | | - ); |
68 | | -}); |
| 84 | + |
| 85 | + return fetch(request).then((response) => { |
| 86 | + if (response.ok) { |
| 87 | + const copy = response.clone(); |
| 88 | + caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); |
| 89 | + } |
| 90 | + return response; |
| 91 | + }); |
| 92 | + }), |
| 93 | + ); |
| 94 | + }); |
| 95 | +} |
0 commit comments