본문 바로가기
C.W.K.
Stream
Lesson 02 of 06 · published

manifest.json 안에 뭐가 들어가?

~12 min · mv3, manifest, schema, clipdeck, hands-on

Level 0Extension 입덕
0 XP0/56 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"manifest.json은 extension의 출생증명서야. Chrome이 가장 먼저 읽는 파일이고, 가장 먼저 거절하는 파일이야."

세 필드짜리 manifest

Chrome은 정확히 세 개 필드만 있는 manifest를 받아 줘. 쓸 만한 건 안 되지만 — load는 돼.

저게 바닥이야. 다른 모든 거 — popup / side panel / background worker / content script — 다 이 세 필수 field 위에 쌓는 거. 이 바닥을 알아야 안 쓸 15 개 필드를 cargo-cult 안 해.

Field의 세 단계

manifest field를 세 층으로 생각해:

  • 필수 — Chrome이 이게 없으면 load 자체를 거부해. 딱 셋: manifest_version / name / version.
  • 강력 추천 — 없으면 load는 되는데 user experience 망가져. description / icons / default_locale.
  • Surface 조건부 — 그 surface를 쓸 때만 의미 있음. action (toolbar icon + popup) / background (service worker) / content_scripts / side_panel / permissions / host_permissions / content_security_policy / options_ui / commands / web_accessible_resources 등 십여 개.

안 쓰는 surface의 조건부 field를 넣어 두는 건 해롭진 않아. 그냥 군더더기야. 반대로 쓰는 surface의 field를 빠뜨리면 조용히 죽어. extension은 멀쩡히 load 되는데 아무 일도 안 일어나지. MV3 디버깅 이야기의 절반이 그 부류 버그야.

필수 3 인방 세부

  • manifest_version: 2024 이후로 반드시 3. 문자열 아닌 숫자.
  • name: 1-75 자, chrome://extensions와 toolbar hover에 표시.
  • version: 1-4 개의 점-구분 정수. "0.1.0" / "1.2" / "3" 다 valid. Chrome이 update 비교할 때 숫자로 비교.

강력 추천 그룹

  • description: 1-132 자, name 아래 한 줄 설명.
  • icons: size (16, 32, 48, 128)를 PNG path로 매핑하는 object. 몇 개 빼먹어도 Chrome이 알아서 다른 size로 대신하지만, 16 + 48 + 128만 채워도 UI surface는 다 덮여.
  • default_locale: _locales/*/messages.json i18n 활성화. 필요할 때까지 미뤄.

Surface 조건부 — 큰 것들

  • action — toolbar icon + popup 설정. default_popup이 클릭 시 렌더할 HTML 파일 가리킴.
  • background — service worker 파일 선언. MV3 형태: { "service_worker": "background.js" }.
  • content_scripts — injection 규칙 배열. matches (URL pattern) / js (script 파일 list) / run_at (document_start | document_end | document_idle) / all_frames (boolean).
  • side_panel — Chrome side panel surface (Chrome 114+)에 load 할 HTML.
  • permissions — API capability (storage / tabs / activeTab / scripting / sidePanel 등).
  • host_permissions — extension이 read/inject 할 수 있는 URL pattern. API permissions와 분리.
  • content_security_policy — extension page가 뭘 load 가능한지 fine-tune. Default 이미 빡빡함. 풀거나 조이는 거 명확히 알 때만 건드려.

ClipDeck의 hello-world manifest

Track 1의 ClipDeck 한테 필요한 건 다섯 개야. name / version / manifest version / toolbar icon / popup. 그게 끝이야. Service worker도, content script도, side panel도, permissions도 없어 — Track 1은 hello-world 니까.

아래 manifest를 clipdeck/manifest.json으로 저장. Popup HTML과 JS는 lesson 4 (hello-clipdeck)에서. icon은 16×16 / 48×48 / 128×128 PNG 아무거나. 단색 사각형도 OK.

필수 셋, 추천 셋, 나머지 조건부. manifest.json에서 기억할 거 하나만이라면 — 이 세 단계, 그리고 추가하는 모든 field는 그게 선언한 surface를 쓰겠다는 약속.
Silent failure는 surface 조건부 field에 산다. "service_worker"에 오타가 나도 load는 돼. content script의 matches를 빠뜨려도 load는 돼. Chrome은 필수 field 에는 바로 깐깐하게 굴지만 optional field 에는 관대하거든. 디버깅은 결국 어느 침묵이 수상한지 알아보는 일이야.

Code

Chrome이 받는 3-field 최소 manifest·json
{
  "manifest_version": 3,
  "name": "Bare Minimum",
  "version": "0.1.0"
}
ClipDeck Track-1 hello-world manifest.json (clipdeck/ 아래 저장)·json
{
  "manifest_version": 3,
  "name": "ClipDeck",
  "version": "0.1.0",
  "description": "Selected-text clipboard you can CRUD from any page.",
  "icons": {
    "16": "icons/icon-16.png",
    "48": "icons/icon-48.png",
    "128": "icons/icon-128.png"
  },
  "action": {
    "default_popup": "popup.html",
    "default_title": "ClipDeck"
  }
}

External links

Exercise

clipdeck/ 디렉토리 편한 곳에 만들어 (Desktop / ~/dev / 어디든 작은 프로젝트 두는 곳). 이 lesson의 ClipDeck hello-world manifest를 clipdeck/manifest.json으로 저장. 그 다음 placeholder PNG 아이콘 셋 — icons/icon-16.png / icons/icon-48.png / icons/icon-128.png — 만들어. 단색 사각형도 OK, 투명 PNG도 OK, 아무 이미지 편집기 (Preview / Photoshop / 온라인 도구) 다 됨. Icon 건너뛰지 마 — Chrome이 없어도 load는 되지만 warning 띄워서, 깨끗한 load 원하면 채워. popup.html 자체는 lesson 4의 일. 지금은 순수하게 manifest scaffold.
Hint
ImageMagick 깔려 있으면 아이콘 셋 한 줄로: for s in 16 48 128. do magick -size ${s}x${s} xc:steelblue icons/icon-${s}.png. done. macOS Preview의 File → Export → PNG (고정 픽셀 dimension)도 됨. 핵심은 정확한 path에 valid PNG 파일을 두는 것 — manifest.json의 icons field가 깔끔하게 resolve 되도록.

Progress

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

댓글 0

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

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