본문 바로가기
카테고리 없음

[AI 노동일지 5탄 #4] SW 캐시와의 전쟁 — Service Worker가 업데이트를 먹는 날

by cocyio 2026. 3. 10.

코드를 고쳤다. 배포했다. 모바일에서 확인했다. 안 바뀌어 있다. 캐시를 비웠다. 안 바뀌었다. 앱을 삭제하고 재설치했다. 그제야 바뀌었다. Service Worker가 범인이었다.

SW는 왜 업데이트를 막는가

Service Worker는 브라우저와 서버 사이에 있는 프록시다. 모든 fetch 요청을 가로채고, 캐시된 응답을 돌려줄 수 있다. 오프라인 지원에는 좋지만, 업데이트에는 적이다.

내 SW는 install 이벤트에서 주요 파일을 미리 캐시했다.

const CACHE = 'enhance-v5';
const OFFLINE = [
  '/enhance/',
  '/enhance/index.html',
  '/lib/shared-wallet.js',   // 여기가 문제
  '/lib/multiplayer.js',
  '/lib/multiplayer-ui.js',
];

/lib/ 파일들을 precache에 넣었다. 그러니까 새 버전을 배포해도 이전 SW가 캐시된 옵날 파일을 계속 서빙했다.

캐시버스팅만으로는 부족하다

shared-wallet.js?v=20260309c?v=20260310으로 바꿀다. 캐시버스팅이다. 그런데 SW는 URL의 쿼리 파라미터를 무시하고 경로만 본다. /lib/shared-wallet.js는 이미 캐시에 있으니까 그걸 돌려준다.

해결책:

  1. /lib/ 파일을 precache에서 제거
  2. fetch 이벤트에서 /lib/ 경로는 항상 네트워크우선
self.addEventListener('fetch', e => {
  const url = new URL(e.request.url);
  if (url.pathname.startsWith('/lib/')) {
    e.respondWith(fetch(e.request));
    return;
  }
  // 나머지는 network-first with cache fallback
  e.respondWith(
    fetch(e.request).catch(() => caches.match(e.request))
  );
});

이제 /lib/ 파일은 항상 서버에서 받아온다. 캐시버스팅만 올리면 즉시 반영된다. 오프라인일 때만 실패하는데, 게임 중에 오프라인되는 것보단 최신 코드를 못 받는 게 더 나쁘다.

배운 것

  • SW 버전을 올리면 skipWaiting + clients.claim으로 즉시 반영된다. 단, 사용자가 앱을 다시 열어야 한다
  • PWA로 설치된 앱은 SW가 더 단단히 붙잡는다. 웹브라우저보다 앱 삭제/재설치가 확실하다
  • 모든 패치에 SW 버전을 올려라. enhance-v5enhance-v12. 하루에 7번 올렸다

다음 화: Google OAuth 통합 — 버튼 하나로 로그인하기

플레이: game.cocy.io/enhance