'use strict'; const CACHE_VERSION = 'v1.0.1'; const STATIC_CACHE_NAME = `static-cache-${CACHE_VERSION}`; const IMAGE_CACHE_NAME = `image-cache-${CACHE_VERSION}`; // App Shell: files that are critical for the app to work offline const APP_SHELL_FILES = [ '/index.html', '/styles.css', '/app.js', '/manifest.webmanifest', '/icons/icon-192x192.png', '/icons/icon-512x512.png' ]; // --- INSTALL Event --- // Caches the App Shell self.addEventListener('install', event => { console.log('[Service Worker] Install'); event.waitUntil( caches.open(STATIC_CACHE_NAME) .then(cache => { console.log('[Service Worker] Caching App Shell'); return cache.addAll(APP_SHELL_FILES); }) ); }); // --- ACTIVATE Event --- // Cleans up old caches self.addEventListener('activate', event => { console.log('[Service Worker] Activate'); event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheName !== STATIC_CACHE_NAME && cacheName !== IMAGE_CACHE_NAME) { console.log('[Service Worker] Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }) ); return self.clients.claim(); }); // --- FETCH Event --- // Intercepts network requests and serves from cache if available self.addEventListener('fetch', event => { const { request } = event; const url = new URL(request.url); // Strategy 1: Stale-While-Revalidate for App Shell (static assets) // Serves from cache immediately for speed, then updates the cache in the background. if (APP_SHELL_FILES.includes(url.pathname) || url.origin === self.location.origin) { event.respondWith( caches.open(STATIC_CACHE_NAME).then(cache => { return cache.match(request).then(response => { const fetchPromise = fetch(request).then(networkResponse => { cache.put(request, networkResponse.clone()); return networkResponse; }); // Return cached response immediately, or wait for network if not in cache return response || fetchPromise; }); }) ); return; } // Strategy 2: Cache-First for images from external origins (e.g., Pexels) // If the image is in the cache, serve it. Otherwise, fetch from network, // cache it, and then serve it. if (url.hostname === 'images.pexels.com') { event.respondWith( caches.open(IMAGE_CACHE_NAME).then(cache => { return cache.match(request).then(response => { if (response) { return response; // Found in cache } // Not in cache, fetch and then cache it return fetch(request).then(networkResponse => { cache.put(request, networkResponse.clone()); return networkResponse; }); }); }) ); return; } // For any other requests, just fetch from the network. event.respondWith(fetch(request)); });