"인터넷에 떠 있는 모든 MV2-시대 튜토리얼이 지뢰밭이야. 패턴은 여전히 자명해 보여 — 그저 더 이상 load 가 안 될 뿐."
Background page → Service worker
가장 큰 단절. MV2 의 persistent background page 는 전체 browser session 동안 메모리에 살아 있었어 — global 에 state 박아두고, long-lived event listener 잡고, cache 쌓고, 다 그대로 유지. MV3 의 service worker 는 event-driven 이고 inactivity 약 30 초 후 evict 돼. Event (message / alarm / tab change / install) 로 깨우면 cold 시작 — global 초기화, in-memory cache 비움, listener 도 파일 위에서부터 재등록.
Migration 패턴: eviction 견뎌야 하는 건 chrome.storage.local 로 (synchronous 느낌, worker 재시작 across 영속). MV2 에서 in-memory state 로 들고 있던 건 storage round-trip 으로 바뀌거나, 매 wake 때 죽는 걸 받아들여.
Blocking webRequest → declarativeNetRequest
MV2 의 chrome.webRequest 는 extension 이 모든 request intercept, header 검사, 동기적으로 block 또는 modify 가능. 그게 ad blocker 의 전체 메커니즘이었어. MV3 가 비-enterprise extension 에 대해 blocking 모드 deprecate 하고 declarativeNetRequest 도입 — rule 기반 시스템, 앞으로 패턴 선언하면 Chrome 이 코드 없이 enforce.
Tradeoff: rule 기반은 더 빠르고 privacy-preserving (extension 이 자기가 안 다루는 request 자체를 못 봄), 근데 덜 유연. 복잡한 ad blocker 들은 matching logic 을 static rule 로 재설계해야 했어. ClipDeck 한테는 이 섹션 정보용 — network interception 필요 없음.
chrome.extension.* → chrome.runtime.*
여러 MV2 API 가 MV3 에서 이름 바뀌거나 chrome.runtime 으로 통합:
chrome.extension.getBackgroundPage()→ 대체 없음 (service worker 는 "가져올" 수 없어 —chrome.runtime.sendMessage로 메시지 보내).chrome.extension.getViews()→ popup/options page 용은 여전히 동작, service worker 는 "볼 수" 없음.chrome.extension.sendMessage→chrome.runtime.sendMessage.chrome.extension.onMessage→chrome.runtime.onMessage.
chrome.extension 쓰는 MV2 스니펫을 복사해 붙이면, 절반은 동작하고 절반은 안 동작. Errors panel 이 빠진 거 한 chrome.extension.X is not a function 으로 보여줘. 보통 find-and-replace 면 충분; Chrome 의 migration 문서에서 symbol 별 mapping 확인.
Persistent state 손실
모든 MV2 dev 가 딱 한 번씩 걸리는 gotcha. 코드는 멀쩡해 보이고, event listening 도 잘 되는데, state 가 랜덤하게 reset 되는 것처럼 보임. 실제로 일어난 일: service worker 가 evict 되고, 다음 event 에 재시작, 파일 위에서부터 다시 실행 — 그래서 아까 채워둔 module-level const cache = new Map() 이 새 빈 Map.
해결: service worker 를 stateless 로 취급하고 chrome.storage.local 을 state layer 로 사용. 각 event handler 위에서 read, 아래에서 write. Track 2 가 이 패턴 깊이 다룸; 지금은 gotcha 자체가 lesson.
Migration 체크리스트
혹시 MV2 extension 을 MV3 로 migrate 해야 한다면 이 list 따라가:
manifest_version: 2 → 3.background.scripts+persistent: true→background.service_worker(단일 파일).- Extension HTML page 의 inline
<script>태그나onclick=handler 다 제거. - 모든
chrome.extension.*호출 찾아서chrome.runtime.*로 매핑 (문서 보고). - Blocking
webRequest→declarativeNetRequestrule (또는 rule 기반이 불가능하면 enterprise policy 로 escalate). - 모든 module-level state 를
chrome.storage.local로 이동. permissions감사:permissions(API) 와host_permissions(URL pattern) 으로 분리.web_accessible_resources형태 확인 — MV3 가 배열을resources/matches가진 object 로 감싸.
이 순서가 MV2 → MV3 migration 의 약 95% 잡아. 남은 5% 는 자기만의 Chrome 문서 deep-dive 가치 있는 edge case.
/develop/ 들어가; MV2-시대 가이드는 /extensions/ 였어.