sw.js (4.2 KB)
1 const CACHE_NAME = 'web-workshop-v1.2'; 2 const urlsToCache = [ 3 '/web_workshop/', 4 '/web_workshop/index.html', 5 '/web_workshop/manifest.json', 6 '/web_workshop/resources/resource-manifest.json', 7 '/web_workshop/resources/css/styles.css', 8 '/web_workshop/resources/js/main.js', 9 '/web_workshop/resources/js/codemirror-bundle.js' 10 ]; 11 12 // Function to discover and cache all files in directories 13 async function cacheDirectoryFiles(cache, directories) { 14 for (const dir of directories) { 15 try { 16 // Try to fetch directory listing 17 const response = await fetch(dir); 18 if (response.ok) { 19 const html = await response.text(); 20 // Extract file links from directory listing 21 const links = html.match(/href="([^"]*\.(png|jpg|jpeg|gif|svg|webp|html|css|js|json|txt|md))"/gi); 22 if (links) { 23 const files = links.map(link => { 24 const match = link.match(/href="([^"]*)"/); 25 return match ? dir + match[1] : null; 26 }).filter(Boolean); 27 28 // Cache each file 29 for (const file of files) { 30 try { 31 await cache.add(file); 32 } catch (e) { 33 console.log(`Failed to cache ${file}:`, e); 34 } 35 } 36 } 37 } 38 } catch (e) { 39 console.log(`Failed to cache directory ${dir}:`, e); 40 } 41 } 42 } 43 44 // Function to cache all resources using the generated manifest 45 async function cacheResources(cache) { 46 try { 47 const response = await fetch('/web_workshop/resources/resource-manifest.json'); 48 if (response.ok) { 49 const manifest = await response.json(); 50 console.log(`Caching ${manifest.images.length} images and ${manifest.resources.length} resources from manifest`); 51 52 // Cache images 53 for (const imagePath of manifest.images) { 54 try { 55 await cache.add(imagePath); 56 console.log(`Cached image: ${imagePath}`); 57 } catch (e) { 58 console.log(`Failed to cache image ${imagePath}:`, e); 59 } 60 } 61 62 // Cache resources 63 for (const resourcePath of manifest.resources) { 64 try { 65 await cache.add(resourcePath); 66 console.log(`Cached resource: ${resourcePath}`); 67 } catch (e) { 68 console.log(`Failed to cache resource ${resourcePath}:`, e); 69 } 70 } 71 } else { 72 console.log('No resource manifest found, skipping resource caching'); 73 } 74 } catch (e) { 75 console.log('Failed to load resource manifest:', e); 76 } 77 } 78 79 // Install service worker and cache resources 80 self.addEventListener('install', event => { 81 event.waitUntil( 82 caches.open(CACHE_NAME) 83 .then(async cache => { 84 // Cache all core files 85 await cache.addAll(urlsToCache); 86 87 // Cache all resources programmatically 88 await cacheResources(cache); 89 }) 90 .then(() => self.skipWaiting()) 91 ); 92 }); 93 94 // Activate service worker and clean up old caches 95 self.addEventListener('activate', event => { 96 event.waitUntil( 97 caches.keys().then(cacheNames => { 98 return Promise.all( 99 cacheNames.map(cacheName => { 100 if (cacheName !== CACHE_NAME) { 101 return caches.delete(cacheName); 102 } 103 }) 104 ); 105 }).then(() => self.clients.claim()) 106 ); 107 }); 108 109 // Fetch strategy: Network first, then cache (for updates when online) 110 self.addEventListener('fetch', event => { 111 event.respondWith( 112 fetch(event.request) 113 .then(response => { 114 // If we got a response, add it to the cache 115 if (response.status === 200) { 116 const responseClone = response.clone(); 117 caches.open(CACHE_NAME) 118 .then(cache => cache.put(event.request, responseClone)); 119 } 120 return response; 121 }) 122 .catch(() => { 123 // Network failed, try cache 124 return caches.match(event.request) 125 .then(response => { 126 if (response) { 127 return response; 128 } 129 // If not in cache and it's a navigation request, serve index.html 130 if (event.request.mode === 'navigate') { 131 return caches.match('/index.html'); 132 } 133 throw new Error('No cached version available'); 134 }); 135 }) 136 ); 137 });