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

Unpacked vs packed — Dev loop와 .crx file

~10 min · unpacked, crx, developer-mode, distribution

Level 0Extension 입덕
0 XP0/56 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"Unpacked는 아빠가 개발할 때 쓰고, packed는 다른 사람이 설치할 때 써. Lesson 2에선 quest 내내 써 온 developer-mode 'Load unpacked' loop과 다른 머신으로 가는 signed .crx의 차이를 짚어."

Unpacked

이 quest 내내 unpacked로 작업해 왔어. chrome://extensions → Developer mode → Load unpacked으로 디스크의 폴더를 그대로 올리는 방식이지. extension은 그 폴더에서 파일을 실시간으로 읽어. content.js를 고치고 reload를 누르는 게 개발 고리의 전부였고. 묶을 것도, 서명할 것도, 어디 올릴 것도 없었어.

unpacked extension은 Chrome이 설치할 때마다 새로 만들어 주는 ID를 받아. 그래서 머신마다 달라져. 개발할 땐 상관없는데, 특정 extension ID를 코드에 박아 넣는 걸 내보내면 (일부 Native Messaging host가 그래) 문제가 돼.

Packed

Packed extension이 .crx file: extension content의 ZIP + 서명 (제어하는 키로 RSA-signed, 또는 Web Store 통해 publish 하면 Chrome 자체로). .crx가 다른 사람의 Chrome에 install 되는 것.

생산 두 방법:

  • chrome://extensions → Pack extension — local 도구. Extension 디렉토리와 (선택적) .pem key file 요청. 첫 실행이 .crx와 fresh .pem 둘 다 생산. future update가 같은 key로 서명하도록 .pem 안전한 곳 유지 (Chrome이 update에 same-key를 same extension으로 다룸).
  • Chrome Web Store — extension 디렉토리의 ZIP upload, Chrome이 서명, .crx가 store에 살아. Public extension의 99% 가 가는 경로.

Same-key update 계약

.pem 이라는 개인 키가 이 extension의 신원을 쥐고 있어. 새 버전을 낼 때마다 같은 .pem으로 서명하는 한, Chrome은 새 .crx를 기존 extension의 업그레이드로 받아들여. user는 새 버전을 받고, storage는 그대로 남고, extension ID도 안 바뀌고. 그런데 이 키를 잃어버리면 그 extension은 사실상 고아가 돼. 새 ID로 다른 extension을 내고 user를 옮겨 오게 하는 수밖에 없어.

Web Store-published extension은 local .pem 필요 없음 — Google이 key 관리. Extension ID가 첫 publish 시 생성되고 절대 안 바뀜.

Distribution 살아남는 dev workflow

권장: unpacked로 개발, primary distribution 경로로 Web Store 통해 publish. Hybrid:

  • Git repo 하나, production permission 가진 single source-of-truth manifest.json.
  • Local dev: npm run builddist/로 출력, chrome://extensions가 dist/에 'Load unpacked' point.
  • Ship 하려면: npm run build && cd dist && zip -r ../clipdeck.zip ., Web Store developer dashboard에 zip upload.
  • Web Store가 서명 / hosting / auto-update 처리. user가 one click으로 install.

Sideloading과 어려운 이유

Chrome이 Web Store 밖에서 .crx file install을 무겁게 제한. Desktop Chrome:

  • Chrome://extensions의 Drag-and-drop install이 동작했지만. 이제 enterprise policy 나 developer-mode unpacked 통해 install 된 extension으로 제한.
  • 직접 .crx URL → Chrome이 "This extension can't be added from this website" 비슷한 거 prompt.
  • Group policy install (Chrome Enterprise)이 sideloaded production extension의 지원 경로.

Chrome Enterprise 없는 dev team 우회: Web Store에 unlisted publish. 각자 unlisted URL에서 install. 나머지는 normal Web Store flow.

Unlisted loophole

Web Store의 'Unlisted' 는 extension이 존재하긴 하는데 검색에도 분류 목록에도 안 뜬다는 뜻이야. URL만 알려 주면 누구나 설치할 수 있고. 제출 절차는 공개랑 똑같아 (개인정보 처리방침, 심사, 전부). 다만 사람들 눈에 띄는 자리에만 안 나오는 거지. Chrome Enterprise를 굴릴 만큼은 아닌 사적인 팀용 extension에 딱 맞는 기본fault.

Development 엔 unpacked, distribution 엔 Web Store 통해 packed. Sideloaded .crx file이 v1 엔 dead end. Web Store (public 이나 unlisted) 사용하든가 enterprise group policy에 commit 하든가.
.pem은 git에 올리지 마. 그 개인 키가 extension에 서명하는 물건이야. 그걸 가진 사람은 개발자인 척 새 버전을 낼 수 있어. 비밀번호처럼 다뤄. repo 밖에 두고, 비밀번호 관리자에 사본을 넣어 두고, 백업은 직접 암호화해. 잃어버려도 Web Store extension 이라면 그렇게까지 치명적이진 않아 (Google이 자체 key 가짐) 하지만 local 서명한 어떤 extension 에도 catastrophic.

Code

Shell — Web Store upload artifact 생산·bash
# Web Store upload 위한 build + zip
npm run build                       # dist/ 출력
cd dist && zip -r ../clipdeck.zip .  # source map / .gitignore 등 exclude
cd ..
ls -la clipdeck.zip                  # 이게 upload 할 것
manifest.json — Chrome의 update 감지에 semver-friendly version 유지·json
{
  "name": "ClipDeck",
  "version": "1.0.0",
  "description": "Save text clips from any page. Browse, search, and copy from a persistent side panel.",
  "manifest_version": 3
}

External links

Exercise

Load unpacked로 trusted development loop를 확인해. Visible edit, Reload, host page refresh까지. Pack extension은 CRX와 private key가 어떻게 생기는지 배우는 optional exercise일 뿐이야. Raw CRX drag-and-drop을 distribution plan으로 삼지 마. Windows/macOS production path는 Web Store 또는 managed enterprise policy야.
Hint
'Load unpacked' 가 silently 아무것도 안 하면, manifest.json에 JSON syntax error 가질 수도 — chrome://extensions 열고 extension card의 'Errors' 버튼 찾기. Reload가 popup.html 변경 안 잡으면, popup도 reload 필요할 수도 (popup 닫고 다시 열기). Background.js 변경은 항상 reload 버튼 필요. popup/panel HTML 편집이 Chrome cache 했으면 가끔 안 함. 생성한 .pem은 아빠만 볼 수 있게 두고 공유하거나 commit하지 마. SSH key처럼 다뤄.

Progress

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

댓글 0

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

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