“인터넷이 끊겨도 작동하는 웹앱, 어떻게 만들 수 있을까?”
웹 성능 향상을 넘어, 이제는 오프라인에서도 동작 가능한 웹앱이 사용자 경험의 기준이 되고 있다.
이번 글에서는 그 핵심인 Service Worker와 캐시 전략, 그리고 이를 활용한 PWA(Progressive Web App) 구현 방식을 정리해보자.
백그라운드에서 브라우저와 별도로 동작하는 JS 스레드
// service-worker.js
self.addEventListener('fetch', (event) => {
event.respondWith(caches.match(event.request));
});
사용자의 요청을 직접 가로채고 응답을 제어할 수 있는 강력한 도구이다.
Service Worker는 Cache API를 통해 리소스를 저장하고 꺼내 쓸 수 있다.
| 전략 | 설명 |
|---|---|
| Cache First | 캐시에 있으면 먼저 사용, 없으면 네트워크 요청 |
| Network First | 항상 네트워크 먼저 요청, 실패 시 캐시 사용 |
| Stale-While-Revalidate | 캐시 즉시 응답 + 백그라운드에서 최신 버전 갱신 |
| Cache Only / Network Only | 극단적인 방식 (별도 조건에서만 사용) |
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('my-cache').then((cache) =>
cache.match(event.request).then((cached) => {
const networkFetch = fetch(event.request).then((res) => {
cache.put(event.request, res.clone());
return res;
});
return cached || networkFetch;
})
)
);
});
PWA는 앱처럼 동작하는 웹앱이다. 핵심은 사용자가 네이티브 앱처럼 느끼도록 만드는 경험 설계이다.
→ 사용자는 "홈 화면에 추가"를 통해 웹앱을 앱처럼 실행 가능
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js');
}
Google에서 만든 서비스 워커 템플릿 자동 생성 도구
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
registerRoute(
({ request }) => request.destination === 'script',
new StaleWhileRevalidate()
);
복잡한 캐시 전략도 한 줄로 구현 가능!
self.skipWaiting() 및 clients.claim()으로 즉시 적용 가능manifest.json 구성도 같이 챙기기서비스 워커는 브라우저의 네트워크 요청을 가로채고 제어할 수 있는 막강한 기능이다. 이를 잘 활용하면 PWA로의 확장이 가능하고, 오프라인에서도 끊김 없는 UX를 제공할 수 있다.