Mercurial
view mrjunejune/src/public/sw.js @ 209:3b47e82ac57e
[MrJuneJune] PWA updates.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 15 Feb 2026 15:43:26 -0800 |
| parents | |
| children |
line wrap: on
line source
// Service Worker for MrJuneJune PWA const CACHE_VERSION = 'v1'; const CACHE_NAME = `mrjunejune-${CACHE_VERSION}`; // Files to cache immediately on install const STATIC_CACHE = [ '/', '/base.css', '/public/epi_all_colors.svg', '/public/fonts/Roboto-Regular.ttf', '/public/fonts/Roboto-Thin.ttf', '/public/fonts/more-sugar.regular.otf', '/public/fonts/more-sugar.thin.otf', ]; // Install event - cache static assets self.addEventListener('install', (event) => { console.log('[SW] Installing service worker...'); event.waitUntil( caches.open(CACHE_NAME).then((cache) => { console.log('[SW] Caching static assets'); return cache.addAll(STATIC_CACHE); }).then(() => { console.log('[SW] Skip waiting'); return self.skipWaiting(); }) ); }); // Activate event - clean up old caches self.addEventListener('activate', (event) => { console.log('[SW] Activating service worker...'); event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_NAME) { console.log('[SW] Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }).then(() => { console.log('[SW] Claiming clients'); return self.clients.claim(); }) ); }); // Fetch event - serve from cache, fallback to network self.addEventListener('fetch', (event) => { const { request } = event; const url = new URL(request.url); // Skip non-GET requests if (request.method !== 'GET') { return; } // Skip chrome-extension and other non-http(s) requests if (!url.protocol.startsWith('http')) { return; } // Skip API calls and media uploads (always go to network) if (url.pathname.startsWith('/api/')) { return; } event.respondWith( caches.match(request).then((cachedResponse) => { if (cachedResponse) { console.log('[SW] Serving from cache:', url.pathname); return cachedResponse; } // Not in cache, fetch from network return fetch(request).then((networkResponse) => { // Only cache successful responses if (!networkResponse || networkResponse.status !== 200 || networkResponse.type === 'error') { return networkResponse; } // Cache specific file types const shouldCache = url.pathname.endsWith('.css') || url.pathname.endsWith('.js') || url.pathname.endsWith('.svg') || url.pathname.endsWith('.png') || url.pathname.endsWith('.jpg') || url.pathname.endsWith('.webp') || url.pathname.endsWith('.woff') || url.pathname.endsWith('.woff2') || url.pathname.endsWith('.ttf') || url.pathname.endsWith('.otf') || url.pathname.startsWith('/blog/') || url.pathname.startsWith('/notes/') || url.pathname === '/'; if (shouldCache) { const responseToCache = networkResponse.clone(); caches.open(CACHE_NAME).then((cache) => { console.log('[SW] Caching new resource:', url.pathname); cache.put(request, responseToCache); }); } return networkResponse; }).catch((error) => { console.log('[SW] Fetch failed:', error); // Return offline page for HTML requests if (request.headers.get('Accept').includes('text/html')) { return caches.match('/offline.html'); } }); }) ); }); // Handle messages from the client self.addEventListener('message', (event) => { if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting(); } if (event.data && event.data.type === 'CLEAR_CACHE') { event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => caches.delete(cacheName)) ); }) ); } });