← 블로그로 돌아가기
튜토리얼 2026년 3월 5일
Chrome Extension 개발 — Manifest V3 실전 가이드
Manifest V3로 Chrome 확장 프로그램을 만드는 실전 과정. 권한, 서비스 워커, 콘텐츠 스크립트.
Chrome Extension Manifest V3 JavaScript React
Manifest V3가 달라진 점
Chrome은 2024년부터 Manifest V2 확장을 스토어에서 제거하기 시작했다. V3로 넘어오면서 바뀐 핵심은 세 가지다.
- 백그라운드 페이지 → 서비스 워커: 상시 실행이 아니라 이벤트 기반으로 동작
chrome.webRequest제한: 요청 차단이declarativeNetRequest로 대체- 원격 코드 실행 금지: CDN에서 JS를 로드해 실행할 수 없음
Marginy를 만들면서 V3에 적응하는 데 가장 오래 걸린 부분은 서비스 워커의 생명주기였다.
프로젝트 구조
marginy-extension/
├── manifest.json
├── src/
│ ├── background/
│ │ └── service-worker.ts
│ ├── content/
│ │ └── inject.ts
│ ├── popup/
│ │ ├── App.tsx
│ │ └── index.html
│ └── utils/
│ └── storage.ts
├── vite.config.ts
└── package.json
Popup은 React로 만들었다. Vite의 멀티 엔트리 빌드로 popup, content script, service worker를 각각 번들링한다.
manifest.json 핵심
{
"manifest_version": 3,
"name": "Marginy",
"version": "1.0.0",
"permissions": ["storage", "activeTab"],
"host_permissions": ["https://*.coupang.com/*", "https://*.naver.com/*"],
"background": {
"service_worker": "src/background/service-worker.js",
"type": "module"
},
"content_scripts": [{
"matches": ["https://*.coupang.com/*"],
"js": ["src/content/inject.js"]
}],
"action": {
"default_popup": "src/popup/index.html"
}
}
permissions와 host_permissions가 분리된 게 V3의 특징이다. 사용자에게 “모든 사이트 접근”을 요청하지 않고 필요한 도메인만 명시할 수 있다.
서비스 워커의 함정
서비스 워커는 30초간 이벤트가 없으면 종료된다. 이건 상태를 메모리에 들고 있으면 안 된다는 뜻이다.
// 잘못된 방법 — 서비스 워커가 종료되면 사라짐
let cachedData = null;
// 올바른 방법 — chrome.storage 사용
chrome.storage.local.set({ cachedData: data });
chrome.storage.local.get('cachedData', (result) => {
// result.cachedData
});
Marginy에서는 계산 결과를 chrome.storage.local에 캐시한다. 서비스 워커가 재시작되어도 데이터가 유지된다.
콘텐츠 스크립트와 메시지 패싱
콘텐츠 스크립트는 웹페이지의 DOM에 접근할 수 있지만, Chrome API는 제한적으로만 쓸 수 있다. 서비스 워커와 통신하려면 메시지 패싱을 사용한다.
// content script → service worker
chrome.runtime.sendMessage({ type: 'CALC_PROFIT', data: productInfo });
// service worker에서 수신
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'CALC_PROFIT') {
const result = calculateProfit(msg.data);
sendResponse(result);
}
return true; // 비동기 응답을 위해 true 반환
});
return true를 빠뜨리면 비동기 응답이 전달되지 않는다. 디버깅하기 어려운 버그다.
개발/디버깅 팁
chrome://extensions에서 “개발자 모드” 활성화 후 “압축해제된 확장 프로그램을 로드합니다” 클릭- 서비스 워커 로그는 확장 프로그램 상세 페이지의 “서비스 워커” 링크에서 확인
- 콘텐츠 스크립트 로그는 해당 웹페이지의 개발자 도구 콘솔에서 확인
chrome.storage.local.get(null, console.log)로 전체 저장 데이터 확인
정리
Manifest V3는 보안과 성능을 위한 변경이지만, 기존 V2 패턴에 익숙하다면 적응 기간이 필요하다. 핵심은 서비스 워커가 언제든 죽을 수 있다는 전제로 설계하는 것이다.