1/** 2 * HANT í¸ë ì¼ ì± Service Worker v9 3 * - í´ìë ì ì ììê³¼ í°í¸ë§ ì íì ì¼ë¡ ìºì± 4 * - Google Maps íì¼ ìºì± (ì¤íë¼ì¸ ì§ë) 5 * - ì¤íë¼ì¸ í´ë°± 6 * - PWA ì¤ì¹ ì§ì 7 * - ë¤ì ì± ìì ì ìì í ì ë°ì´í¸ ì ì© 8 */ 9 10// ë°°í¬ ë²ì ë§ë¤ ì± ì ¸ ìºì를 êµì²´í´ ì´ì HTML·JS ë²ë¤ì´ ë¨ì§ ìê² íë¤. 11const APP_CACHE = "hant-app-v9"; 12const MAP_CACHE = "hant-map-tiles-v2"; 13const FONT_CACHE = "hant-fonts-v1"; 14const OFFLINE_URL = "/offline.html"; 15 16// ê³µê° ííì´ì§ììë§, ì´ì íì´ì§ ì± ì ¸ì´ ê¹¨ì§ `/images/*`를 ê³ì 참조íì§ ìëë¡ 17// ì ì커를 ì¦ì íì±ííë¤. Capacitor Androidë `https://localhost` ë³ë originì´ë¯ë¡ 18// ì´ ì¡°ê±´ì ì ë í¬í¨ëì§ ìì¼ë©° íì¬ ì§ë·GPS ì¸ì ì reloadíì§ ìëë¤. 19const PUBLIC_WEB_HOSTS = new Set(["hantp.com", "www.hantp.com"]); 20 21 22// ì¤ì¹ ì ì¬ì ìºì±í ì± ì ¸ ìì 23const PRECACHE_ASSETS = [ 24 "/", 25 "/offline.html", 26]; 27 28// ââ Install ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 29self.addEventListener("install", (event) => { 30 event.waitUntil( 31 caches.open(APP_CACHE).then((cache) => { 32 return cache.addAll(PRECACHE_ASSETS).catch(() => { 33 // ì¼ë¶ ìì ìºì± ì¤í¨ ì 무ì (Vite ë¹ë í´ì ë문ì ì íí ê²½ë¡ ë¶ëª ) 34 }); 35 }) 36 ); 37 if (PUBLIC_WEB_HOSTS.has(self.location.hostname)) { 38 self.skipWaiting(); 39 } 40 // íì¬ Android í면·GPS·ê´ë¦¬ ë©ë´ë¥¼ ì ì§í ì±, 모ë 기존 í´ë¼ì´ì¸í¸ê° ë«í ë¤ì ì± ììì íì±ííë¤. 41 // ì´ë¦° ì±ì ê°ì ë¡ reloadíë©´ í¸ëí¹ íë©´ì´ íì¼ë¡ ëìê°ë íê·ê° ì길 ì ìë¤. 42}); 43 44// ââ Activate âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 45self.addEventListener("activate", (event) => { 46 const currentCaches = [APP_CACHE, MAP_CACHE, FONT_CACHE]; 47 event.waitUntil( 48 caches.keys().then((keys) => 49 Promise.all( 50 keys 51 .filter((key) => !currentCaches.includes(key)) 52 .map((key) => caches.delete(key)) 53 ) 54 ) 55 ); 56 self.clients.claim(); 57}); 58 59// ââ Fetch âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 60self.addEventListener("fetch", (event) => { 61 const { request } = event; 62 const url = new URL(request.url); 63 64 // API ìì²ì ìºì±íì§ ìì 65 if (url.pathname.startsWith("/api/")) return; 66 67 // GET ìì²ë§ ì²ë¦¬ 68 if (request.method !== "GET") return; 69 70 // Google Fonts ìºì± (í°í¸ë ì¥ê¸° ìºì±) 71 if ( 72 url.hostname.includes("fonts.googleapis.com") || 73 url.hostname.includes("fonts.gstatic.com") 74 ) { 75 event.respondWith( 76 caches.open(FONT_CACHE).then(async (cache) => { 77 const cached = await cache.match(request); 78 if (cached) return cached; 79 try { 80 const response = await fetch(request); 81 if (response.ok) cache.put(request, response.clone()); 82 return response; 83 } catch { 84 return cached ?? new Response("Offline", { status: 503 }); 85 } 86 }) 87 ); 88 return; 89 } 90 91 // Google Maps íì¼ ë° API ìºì± (ìºì ì°ì - ì¤íë¼ì¸ ì§ë ì§ì) 92 if ( 93 url.hostname.includes("maps.googleapis.com") || 94 url.hostname.includes("maps.gstatic.com") || 95 url.hostname.includes("khms0.googleapis.com") || 96 url.hostname.includes("khms1.googleapis.com") || 97 url.hostname.includes("mts0.google.com") || 98 url.hostname.includes("mts1.google.com") || 99 url.hostname.includes("mts2.google.com") || 100 url.hostname.includes("mts3.google.com") 101 ) { 102 event.respondWith( 103 caches.open(MAP_CACHE).then(async (cache) => { 104 const cached = await cache.match(request); 105 if (cached) return cached; 106 try { 107 const response = await fetch(request); 108 if (response.ok && response.status === 200) { 109 // íì¼ ì´ë¯¸ì§ë§ ìºì± (JS/JSON ì ì¸) 110 const contentType = response.headers.get("content-type") ?? ""; 111 if (contentType.includes("image") || contentType.includes("octet-stream")) { 112 cache.put(request, response.clone()); 113 } 114 } 115 return response; 116 } catch { 117 return cached ?? new Response("Offline", { status: 503 }); 118 } 119 }) 120 ); 121 return; 122 } 123 124 // 기í ì¸ë¶ ëë©ì¸ - ìºì± ìì´ íµê³¼ 125 if (url.origin !== self.location.origin) return; 126 127 // HTML·API ì¸ ë´ë¶ ìì²ì ë¤í¸ìí¬ë¥¼ ì°ì íë¤. ì´ì ìë 모ë same-origin GETì 128 // ìºìí´ íì´ì§Â·ë²ë¤Â·ìëµì´ ëì ëê³ ì´ì ë°°í¬ê° ì¤ë ë¨ì ì ììë¤. 129 const isHashedAsset = /^\/assets\/.+\.(js|css|woff2?|png|jpg|jpeg|webp|svg)$/i.test(url.pathname); 130 event.respondWith( 131 fetch(request) 132 .then((response) => { 133 if (response.ok && isHashedAsset) { 134 const clone = response.clone(); 135 caches.open(APP_CACHE).then((cache) => cache.put(request, clone)); 136 } 137 return response; 138 }) 139 .catch(async () => { 140 const cached = await caches.match(request); 141 if (cached) return cached; 142 // HTML ìì²ì´ë©´ ì¤íë¼ì¸ íì´ì§ ë°í 143 if (request.headers.get("accept")?.includes("text/html")) { 144 const offlinePage = await caches.match(OFFLINE_URL); 145 if (offlinePage) return offlinePage; 146 // ë£¨í¸ ìºìë ìë 147 const rootPage = await caches.match("/"); 148 if (rootPage) return rootPage; 149 } 150 return new Response("ì¤íë¼ì¸ ìíì ëë¤", { 151 status: 503, 152 headers: { "Content-Type": "text/plain; charset=utf-8" }, 153 }); 154 }) 155 ); 156});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.