--- id: web-service-worker-patterns title: Service Worker 캐싱 전략 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [web, service-worker, pwa, caching, offline, vibe-coding] tech_stack: { language: "TypeScript / Workbox", applicable_to: ["Web", "PWA"] } applied_in: [] aliases: [cache-first, network-first, stale-while-revalidate, PWA] --- # Service Worker 캐싱 전략 > Service Worker = 네트워크 인터셉터. 5가지 표준 전략 — Cache-First / Network-First / Stale-While-Revalidate / Network-Only / Cache-Only — 자원 종류에 따라 골라 쓴다. 한 SW 안에 여러 전략 혼용 OK. ## 📖 핵심 개념 - `install` 이벤트: precache (빌드 시 알려진 자원). - `fetch` 이벤트: 매 요청 인터셉트. - `activate` 이벤트: 옛 캐시 청소. - 자원 별 다른 정책 적용. ## 💻 코드 패턴 (Workbox 기반) ```ts // sw.ts import { precacheAndRoute } from 'workbox-precaching'; import { registerRoute } from 'workbox-routing'; import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'; import { ExpirationPlugin } from 'workbox-expiration'; // 빌드 시 자동 주입 precacheAndRoute(self.__WB_MANIFEST); // 1. 정적 자산 — Cache-First (해시 파일명이라 immutable) registerRoute( ({ request }) => ['style', 'script', 'font'].includes(request.destination), new CacheFirst({ cacheName: 'static-v1', plugins: [new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60 })], }) ); // 2. 이미지 — Stale-While-Revalidate registerRoute( ({ request }) => request.destination === 'image', new StaleWhileRevalidate({ cacheName: 'images-v1', plugins: [new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 7 * 24 * 60 * 60 })], }) ); // 3. API — Network-First with timeout registerRoute( ({ url }) => url.pathname.startsWith('/api/'), new NetworkFirst({ cacheName: 'api-v1', networkTimeoutSeconds: 3, }) ); ``` ### 5가지 전략 요약 | 전략 | 흐름 | 사용처 | |---|---|---| | Cache-First | 캐시 → 없으면 네트워크 | hashed 정적 자산 | | Network-First | 네트워크 → 실패시 캐시 | 자주 변하는 데이터 | | Stale-While-Revalidate | 캐시 즉시 + 백그라운드 재검증 | 이미지, 자주 보지만 약간 stale OK | | Network-Only | 캐시 안 씀 | 결제, 민감 데이터 | | Cache-Only | 네트워크 안 씀 | 오프라인 전용 자원 | ## 🤔 의사결정 기준 | 자원 | 전략 | |---|---| | JS/CSS (hashed) | Cache-First + 만료 30d | | 이미지 | Stale-While-Revalidate + 100 entries cap | | HTML | Network-First (3s timeout) → cached fallback | | API GET (read) | Network-First or stale-while-revalidate | | API POST (write) | Network-Only (절대 캐시 X) | | Offline page | Cache-Only | ## ❌ 안티패턴 - **모든 요청 Cache-First**: API 응답이 영원히 stale. 사용자 답답. - **버전 관리 없는 캐시 이름**: 새 deploy 가 옛 캐시 못 청소. `static-v1` → `static-v2`. - **POST 요청 캐싱**: 사고. 명시적 Network-Only. - **manifest 없는 precache**: 빌드 타임 정보 안 들어가서 누락. - **`activate` 에서 옛 캐시 안 지움**: 무한 누적 → quota exceeded. - **localhost 에서 SW 등록 후 디버깅 어려움**: chrome devtools "Update on reload" + "Bypass for network" 활용. - **사용자 알림 없이 새 SW 활성화**: 페이지가 갑자기 다른 버전. `skipWaiting` + `clientsClaim` 신중히. 보통 사용자에게 "새 버전 있음, 새로고침" prompt. ## 🤖 LLM 활용 힌트 - Workbox 또는 vite-plugin-pwa 사용 가정. - 자원 별 전략 매핑 표를 먼저 만들고 코드 작성. - 새 SW 활성화는 사용자 동의 후 (UX 보호). ## 🔗 관련 문서 - [[Web_HTTP_Cache_Headers]] - [[Backpressure_Patterns]]