C.W.K.
Stream
Lesson 01 of 06 · published

Service Worker 가 도대체 뭐야?

~10 min · service-worker, background, mv3, lifecycle, concepts

Level 0Extension 입덕
0 XP0/54 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"Service worker 는 깨어나서, 한 가지 하고, 다시 잠드는 프로세스야. Extension 을 '대부분 잠들어 있다' 는 가정으로 설계하면, MV3 의 전체 디자인이 제자리에 딸각 들어와."

Background, 다시 상상하기

MV2 의 background page 는 Chrome 이 도는 동안 메모리에 계속 남아 있는 long-lived HTML 문서 + JavaScript runtime 이었어. 편하긴 했지 — global 에 state 박고, WebSocket 연결 유지, timer 돌리고. 비쌌고 — 모든 install 된 extension 이 user 가 쓰든 안 쓰든 메모리 비용. 보안 약점도 — long-lived 프로세스 한 번 compromise 되면 Chrome 재시작까지 compromise 유지.

MV3 가 persistent page 를 service worker 로 교체: Chrome 이 필요할 때 spin up 하고 idle 하면 tear down 하는 event-driven JavaScript context. PWA 를 굴리는 같은 개념을 extension 의 background context 로 재사용. 가볍고, 악용하기 어렵고, state 를 명시적으로 다루도록 강제 — 메모리에 기대지 마.

Service Worker 의 해부

Service worker 는 단일 JavaScript 파일 (HTML 없음, DOM 없음, window 없음). 자기 thread 에서 돌고 popup / content script 와 격리. 파일 위 부분이 매 wake-up 마다 실행, 거기 등록된 listener 가 event 받음.

window / document 못 써. localStorage 도 없음. fetch 됨. self 가 global. chrome.* API 는 popup 과 동일하게 동작, 한 가지만 다름: async 작업은 worker eviction 전에 완료해야 함 (또는 listener 에서 true 반환).

Service Worker Lifecycle

다섯 상태가 중요:

  • Installing — Chrome 이 worker 등록; 파일 위 부분 한 번 실행.
  • Activating — 등록 성공; chrome.runtime.onInstalled fire.
  • Running — event 가 worker 깨움; 능동 실행 중.
  • Idle — event 발동 없음, in-flight async 없음; Chrome 의 eviction clock 째깍.
  • Evicted — Chrome 이 worker 종료. Module-level state 사라짐. Listener 는 여전히 등록 상태 (Chrome 의 worker 기록에 살고, worker memory 에 사는 게 아님).

다음 event — 등록된 listener 발동 — 이 worker 를 cold 로 깨움. Chrome 이 파일 위에서부터 다시 실행 (중요: listener 재등록이 chrome.runtime.onMessage.addListener(...) 를 파일 위에서 다시 실행함으로써 일어남) 한 다음 event dispatch.

왜 Idle eviction 이 중요해

세 가지 이유:

  • 메모리 — 평균 user 는 install 된 extension 의 service worker 가 어느 순간이든 0 개 돌고 있음. Extension 이 능동적으로 일할 때만 메모리 spike.
  • 보안 — Compromise 된 worker 가 데이터 exfiltrate 노리며 무한정 앉아 있을 수 없음; evict 되고, cold 로 재시작, Chrome 의 permission check 다시 돔.
  • 성능 — Chrome 의 renderer process 가 always-on extension 코드로 비대해지지 않음.

비용은 정신적 전환: event 너머로 in-memory state 를 신뢰하지 마. 중요한 거는 chrome.storage 로. Ephemeral 한 거는 잃어도 OK.

ClipDeck 이 이걸로 뭐 할 거야

Track 2 를 통해 ClipDeck 이 첫 비-UI surface 얻음. Lesson 2 가 manifest 통해 background.js 등록. Lesson 3 이 event-driven lifecycle 깊이 들어감. Lesson 4 가 chrome.storage.local 을 state layer 로 도입. Lesson 5 가 popup ↔ worker message passing wire. Lesson 6 이 묶음: chrome.tabs.onUpdated 가 storage 의 방문 counter 증가, popup 이 running total 표시.

Track 2 끝나면 ClipDeck 이 더 이상 순수 UI 아냐 — background 에서 browser 관찰하고 state 누적. CRUD 의 R 워밍업.

모든 service worker 를 방금 깨어난 것처럼 설계. Storage 에서 state read, 일 하고, state 다시 write, 매 순간 evict 될 수 있다고 예상. 패턴은 짧고, 집중되고, module-level 에서 stateless.
cwkPippa 의 embeds/chrome/background.js 처음 읽었을 때, 얼마나 작은지 놀랐어 — 총 4 KB. Per-tab context cache 를 Map 으로 (hot tab 한해서 Chrome 이 eviction 전에 보통 wake 하니까 acceptable), 최신 payload 를 side panel 로 forward, request-context handler 노출. 끝. Brain 은 cwkPippa 상단에 머물러. Worker 는 그냥 plumbing — 그게 모든 MV3 background script 의 맞는 형태야.

Code

최소 MV3 service worker — listener 만, module-level state 없음·javascript
// background.js — minimum viable service worker.
// Runs at the top on every wake-up.

console.log("[ClipDeck SW] alive at", new Date().toISOString());

chrome.runtime.onInstalled.addListener((details) => {
  console.log("[ClipDeck SW] onInstalled:", details.reason);
});

chrome.runtime.onStartup.addListener(() => {
  console.log("[ClipDeck SW] onStartup — Chrome launched");
});

// Notice: no module-level state. No setInterval. No fetch loops.
// Every event handler is the entire unit of work.
MV3 service worker lifecycle — 시각화·text
[install / first load]
     │
     ▼
  [activating] ──onInstalled fires──┐
     │                              │
     ▼                              ▼
  [running] ◀────event arrives──── [idle, ~30s]
     │                              │
     │                              ▼
     └───────────────────────── [evicted]
                                    │
                                    ▼
                            (next event wakes cold)

External links

Exercise

chrome://serviceworker-internals/?devtools 를 새 tab 에서 열어 — 이게 Chrome 의 머신 위 모든 등록된 service worker (extension + PWA) 깊이 view. ClipDeck 검색 (Ctrl+F). Track 1 의 ClipDeck 은 background.service_worker 선언 없으니까 목록에 안 나와야 함. Lesson 2 가 그걸 바꿈. 여기 온 김에 install 한 PWA 한두 개 (Notion / Spotify / Google Docs) 찾아서 service worker entry 관찰 — Status (RUNNING / STOPPED), URL, registration ID. 지금 RUNNING worker 가진 extension / PWA 와 STOPPED 인 거 메모.
Hint
chrome://serviceworker-internals 는 public-facing UI 보다 verbose, 모든 state 전환 보여줘. ClipDeck 이 Lesson 2 전에 거기 나타나면, 어디선가 background.service_worker 실수로 추가한 거 — manifest 확인. 목록의 stopped worker 는 정상 — 방금 설명한 idle-eviction 동작.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.