왜 아무도 서비스 워커를 안 쓸까? 그 이유와 활용법
서비스 워커(Service Worker) API는 2018년부터 지원되었으나, 많은 중소기업 개발자들이 도입 필요성 미인지로 인해 활용하지 않고 있음
서비스 워커는 애플리케이션과 네트워크 사이의 프록시 역할을 하며, 캐싱, 푸시 알림, 백그라운드 동기화 등 다양한 기능 제공
슬랙(Slack)은 웜 부트(Warm Boot) 전략으로 초기 로딩 속도를 50% 단축하고 오프라인 지원을 강화했으며, 먹스(Mux)는 비디오 스트리밍 화질 제어에 활용함
Vite 배포 오류 경험을 통해 구버전 에셋의 영속성 보장과 신버전으로의 조용한 전환을 서비스 워커로 해결함
서비스 워커의 핵심 특징과 작동 방식
서비스 워커는 독립적인 스레드에서 실행되는 자바스크립트 파일로, 애플리케이션과 네트워크 요청 사이에 위치하여 프록시(Proxy) 역할을 수행함.
네트워크 경로 상 위치: 모든 리소스 요청을 가로채 캐시 응답, 네트워크 응답, 또는 직접 생성한 응답을 반환할 수 있음.
페이지보다 긴 생명주기: 브라우저 탭이 닫힌 후에도 푸시 알림, 백그라운드 동기화 등 백그라운드 작업을 처리할 수 있음.
DOM 접근 불가: 웹 페이지와 `postMessage` API로만 통신하며, 자체 라이프사이클을 가짐.
이러한 특징은 초기 로딩 성능 개선, 오프라인 지원, 백그라운드 작업 수행 등 다양한 유스케이스를 가능하게 함.
슬랙(Slack)의 서비스 워커 기반 '웜 부트' 전략
슬랙은 서비스 워커의 Cache API와 IndexedDB를 활용하여 초기 로딩 성능을 획기적으로 개선함. 첫 방문 시 모든 에셋을 캐싱하는 '콜드 부트(Cold Boot)'와 달리, 재방문 시에는 캐시된 에셋과 Redux 스토어 복원으로 UI를 즉시 렌더링하는 '웜 부트(Warm Boot)'를 구현함.
버전 관리: 배포 시마다 Webpack 플러그인으로 에셋 매니페스트 생성, 배포 타임스탬프 기반 캐시 버킷 관리, 7일 후 캐시 삭제로 캐시 무효화(Cache Invalidation) 문제 해결.
지연 시간 단축: 웜 부트 시 평균 로딩 시간 50% 단축, 백그라운드에서 최신 데이터 로딩으로 사용자 경험(User Experience) 향상.
오프라인 지원: 네트워크 연결 없이도 앱 시작 및 메시지 읽기, 오프라인 상태에서 메시지 작성 후 자동 동기화 기능 제공.
먹스(Mux)의 서비스 워커를 활용한 비디오 스트리밍 제어
먹스는 서비스 워커를 이용해 HLS 비디오 스트림의 매니페스트 파일을 실시간으로 수정하여 어댑티브 비트레이트(Adaptive Bitrate) 기능의 과도한 화질 저하 문제를 해결함.
매니페스트 수정: 플레이어 앞단에 배치된 서비스 워커가 `.m3u8` 매니페스트 요청을 가로채, 720p 미만 해상도 렌디션을 제거하여 사용자에게 제공.
유연한 적용: 브라우저 서비스 워커와 동일한 `fetch` 이벤트 API를 사용하는 Cloudflare Workers 같은 에지 런타임(Edge Runtime)에도 수정 없이 적용 가능.
실시간 데이터 재작성: HTTP를 통해 전송되는 텍스트 기반 데이터를 실시간으로 재작성하여 클라이언트 측에서 원하는 대로 제어할 수 있음을 입증함.
Vite 배포 오류 해결을 위한 서비스 워커 도입
필자는 Vite의 콘텐츠 해시 기반 파일명 전략으로 인한 동적 임포트 오류(Dynamically Imported Module Error)를 해결하기 위해 서비스 워커를 도입함. 배포 시 사라지는 이전 버전의 에셋 요청으로 인해 발생하는 404 오류를 방지하고자 함.
두 가지 핵심 문제 해결: 구버전 에셋의 영속성 보장 (서비스 워커 캐시 활용) 및 신버전으로의 조용한 전환 (백그라운드 버전 감시 및 캐싱).
버전 관리 시스템: `version.json` 파일을 통해 최신 버전 정보를 주기적으로 폴링(Polling)하고, 신규 에셋을 백그라운드에서 미리 캐싱함.
안정적인 전환: 사용자가 라우트 이동 시점에 `window.location.reload()`를 호출하여 새로고침을 유도, `Cache-Control: no-cache` 설정으로 안정적인 HTML 로딩 보장.
서비스 워커 라이프사이클의 복잡성과 도입 장벽
많은 개발자들이 서비스 워커 도입을 꺼리는 주된 이유는 복잡한 라이프사이클(Lifecycle) 관리의 어려움 때문임. 서비스 워커는 등록 후 즉시 활성화되지 않으며, `clients.claim()`이나 `skipWaiting()` 같은 API를 사용해도 예상치 못한 동작을 일으킬 수 있음.
활성화 지연: 페이지 이동 전까지 워커 제어가 적용되지 않거나, `waiting` 상태에 머무르는 문제 발생.
캐싱 전략 실패: 잘못된 캐싱 전략 설계로 사용자에게 만료된 앱을 계속 서빙하는 '캐시 참사(Cache Horror Story)' 발생 가능성.
도입 비용: 이러한 복잡성 때문에 Workbox 같은 라이브러리 활용이 권장되나, 여전히 서비스 워커의 근본적인 동작 원리에 대한 이해가 필요함.
서비스 워커의 숨겨진 활용 사례: Partytown과 MSW
서비스 워커는 오프라인 지원 외에도 메인 스레드 외부에서 서드파티 스크립트를 실행하거나 테스트 환경에서 API 모킹하는 데에도 활용됨.
Partytown: 동기식 XMLHttpRequest API를 활용하여 웹 워커 내 스크립트가 메인 스레드 DOM 속성에 접근하는 것처럼 보이게 함. 이는 Core Web Vitals 성능 저하를 방지하는 효과를 가져옴.
Mock Service Worker (MSW): 실제 네트워크 요청 대신 모킹된 응답을 반환하여 테스트 환경의 격리성과 재현성을 높임.
이처럼 서비스 워커는 네트워크 경계에서의 데이터 제어 및 격리라는 강력한 기능을 제공하며, 다양한 고급 유스케이스에 적용될 수 있음.