sw.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. // Offline app-shell cache. API calls are never cached. The shell (HTML/JS/CSS)
  2. // is NETWORK-FIRST so code updates land immediately for online clients (a stale
  3. // cache-first app.js is why "?job=" showed no model on an old install); heavy,
  4. // stable assets (three.js vendor, demo.glb, icons) stay cache-first.
  5. const CACHE = 'genrecon-v4'; // bump on shell change so clients refresh
  6. const SHELL = [
  7. './', './index.html', './styles.css', './app.js', './viewer.js', './manifest.webmanifest',
  8. './demo.glb', './icons/icon-192.png', './icons/icon-512.png',
  9. './vendor/three.module.js',
  10. './vendor/jsm/loaders/GLTFLoader.js', './vendor/jsm/utils/BufferGeometryUtils.js',
  11. './vendor/jsm/math/Octree.js', './vendor/jsm/math/Capsule.js',
  12. ];
  13. self.addEventListener('install', (e) => {
  14. e.waitUntil(caches.open(CACHE).then((c) => c.addAll(SHELL)).then(() => self.skipWaiting()));
  15. });
  16. self.addEventListener('activate', (e) => {
  17. e.waitUntil(
  18. caches.keys()
  19. .then((ks) => Promise.all(ks.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
  20. .then(() => self.clients.claim()),
  21. );
  22. });
  23. self.addEventListener('fetch', (e) => {
  24. const req = e.request;
  25. const url = new URL(req.url);
  26. if (url.pathname.startsWith('/api/')) return; // dynamic — straight to network, never cached
  27. const isVendor = url.pathname.includes('/vendor/') || url.pathname.endsWith('.glb') || url.pathname.includes('/icons/');
  28. const isShell = !isVendor && (req.mode === 'navigate' || /\.(?:js|css|webmanifest)$/.test(url.pathname));
  29. if (isShell) {
  30. // Network-first: always try the latest code, cache it, fall back to cache offline.
  31. e.respondWith(
  32. fetch(req)
  33. .then((r) => { const copy = r.clone(); caches.open(CACHE).then((c) => c.put(req, copy)); return r; })
  34. .catch(() => caches.match(req).then((r) => r || caches.match('./index.html'))),
  35. );
  36. } else {
  37. // Cache-first for heavy, stable assets (three.js, demo.glb, icons).
  38. e.respondWith(caches.match(req).then((r) => r || fetch(req)));
  39. }
  40. });