빠른 흐름
json
{
"name": "my-tool",
"version": "1.0.0",
"type": "module",
"bin": {
"my-tool": "./bin/cli.js"
},
"files": ["bin", "dist", "README.md"],
"exports": {
".": "./dist/index.js"
}
}javascript
#!/usr/bin/env node
// bin/cli.js
import { run } from "../dist/index.js";
run(process.argv.slice(2));배포 흐름
먼저 구분해 둘 기본형은 아래입니다.
- CLI 엔트리 노출:
bin - 라이브러리 공개 표면:
exports - 배포 파일 허용 목록:
files - 사전 검증:
npm publish --dry-run - scoped 공개 배포:
npm publish --access public
이 패키지가 라이브러리인지 CLI인지 먼저 구분한다
둘 다 될 수는 있지만, 배포 검토 기준이 다릅니다. 라이브러리면 exports, 타입, 배포 파일 경계가 중요하고, CLI면 bin, shebang, 실행 권한이 먼저입니다.
배포 파일은 허용 목록으로 관리한다
files를 비워두면 테스트, 소스, 임시 파일까지 같이 올라가기 쉽습니다. 배포 카드에서는 "무엇을 포함할지"보다 "무엇만 포함할지"가 더 중요합니다.
dry-run은 선택이 아니라 마지막 필수 확인이다
버전, 포함 파일, 잘못된 비공개 파일 노출은 실제 publish 전에 거의 다 여기서 잡힙니다.
scoped 패키지는 공개 플래그를 같이 본다
@scope/name 패키지는 공개 배포 시 --access public을 빠뜨리기 쉽습니다. 조직 패키지를 다룰 때 특히 같이 떠올려야 합니다.
CLI와 라이브러리를 같이 배포하면 경계를 더 분명히 둔다
하나의 패키지에서 bin과 exports를 함께 내보내는 건 가능하지만, 사용자가 import할 표면과 실행할 엔트리가 섞이지 않게 정리해야 합니다.
즉 npm publish 흐름과 패키지 public surface 설계를 같이 봐야 합니다.
언제 bin을 붙일까
체크포인트
- CLI 명령 노출:
bin - Unix 실행 가능하게: shebang
- 배포 파일 경계:
files - 사전 검증:
npm publish --dry-run - scoped 공개 배포:
npm publish --access public - 프리릴리즈 태그:
npm publish --tag beta - CLI와 라이브러리를 함께 배포하면
bin과exports경계를 같이 점검
주의할 점
CLI 패키지는 bin만 적는다고 끝나지 않는다. shebang과 실행 권한이 빠지면 설치는 되는데 명령이 안 도는 애매한 상태가 된다.
참고 링크
2 sources