패키지 관리자
pkg 명령은 package.json 생성, JSH 패키지 설치, 패키지 스크립트 실행을 담당합니다.
JSH 애플리케이션이 /work 같은 프로젝트 디렉터리 안에서 의존성을 관리할 때 사용합니다.
개요
pkg 명령은 다음 작업을 지원합니다.
- 새
package.json생성 node_modules에 의존성 설치- GitHub 프로젝트를 원하는 디렉터리로 복사하고 그 위치에서 프로젝트 의존성 설치
package-lock.json유지package.json의scripts실행- 설치한 패키지의
bin항목으로 실행 wrapper 생성 - 의존성과 생성된 wrapper 제거
package.json
pkg는 package.json을 선택된 패키지 루트의 manifest로 취급합니다.
일반 프로젝트 설치에서는 현재 디렉터리 또는 --dir로 지정한 디렉터리가 그 루트입니다.
pkg install -g, pkg uninstall -g에서는 패키지가 /work/node_modules 아래에 설치되지만 /work/package.json, /work/package-lock.json은 만들지 않습니다.
최소한의 프로젝트 manifest 예시는 다음과 같습니다.
{
"name": "demo-app",
"version": "1.0.0",
"scripts": {
"start": "./main.js"
},
"dependencies": {
"generic-pkg": "^1.2.0",
"github.com/acme/demo": "#tag=v1.1.0"
}
}pkg가 주로 사용하는 필드는 다음과 같습니다.
| 필드 | 타입 | 설명 |
|---|---|---|
name | String | 프로젝트 패키지 이름 |
version | String | 프로젝트 버전 |
scripts | Object | pkg run으로 실행할 이름 있는 명령행 |
dependencies | Object | 패키지 이름과 버전 지정자 맵 |
추가 설명:
scripts는 현재 프로젝트 manifest의 항목이며pkg run만 사용합니다.dependencies는 선택된 패키지 루트 기준으로pkg install,pkg uninstall이 갱신합니다.- 일반 프로젝트 설치에서는 재현 가능한 설치를 위해
pkg가package.json옆에package-lock.json도 기록합니다. bin은node_modules아래 각 설치 패키지의 자체package.json에서 읽어 오며,pkg는 그것을 바탕으로node_modules/.binwrapper를 생성합니다.
예를 들어 pkg install -g github.com/acme/demo를 실행하면 설치된 패키지 manifest는 /work/node_modules/github.com/acme/demo/package.json이고, pkg의 전역 metadata는 /work/node_modules/.pkg/ 아래에 저장됩니다.
pkg init
현재 프로젝트 디렉터리에 새 package.json을 생성합니다.
사용 형식
pkg init [options] <name>옵션
-C, --dir <dir>현재 작업 디렉터리 대신 지정한 프로젝트 디렉터리를 사용합니다.-h, --help도움말을 표시합니다.
사용 예시
/work > pkg init demo-app
Created /work/package.json생성되는 파일에는 빈 scripts, dependencies 객체가 포함됩니다.
{
"name": "demo-app",
"version": "1.0.0",
"scripts": {},
"dependencies": {}
}pkg install
package.json에 선언된 의존성을 설치하거나, 단일 패키지 요청을 설치하면서
package.json, package-lock.json을 함께 갱신합니다.
사용 형식
pkg install [options] [name]옵션
-C, --dir <dir>현재 작업 디렉터리 대신 지정한 프로젝트 디렉터리를 사용합니다.-g, --global--dir를 무시하고 전역 패키지 디렉터리에 설치합니다. 이 디렉터리는 전역 패키지 전용이므로 일반 프로젝트 루트로 사용하면 안 됩니다.-h, --help도움말을 표시합니다.
name을 생략하면 선택된 프로젝트 manifest에 선언된 기존 의존성을 설치합니다. -g에서는 /work/node_modules/.pkg/ 아래의 내부 metadata를 사용합니다.
전역 설치
pkg install -g <name>은 /work/node_modules에 설치합니다.
-g가 있으면 pkg는 --dir을 무시합니다.
전역 패키지 디렉터리는 전역 패키지와 metadata를 위한 예약 영역이므로, 일반 프로젝트는 /work 자체가 아니라 /work/my-app 같은 하위 디렉터리에 만들어야 합니다.
이 방식으로 다음 두 가지를 처리할 수 있습니다.
binwrapper를 셸PATH에서 바로 실행할 수 있는 전역 명령 패키지 설치- 전역 패키지 디렉터리에 공유 라이브러리 패키지 설치
예시는 다음과 같습니다.
/work > pkg install -g github.com/acme/demo
Installed github.com/acme/demo#tag=v1.1.0npm 패키지
패키지 이름이 GitHub 저장소 경로가 아니면 npm registry에서 설치합니다.
/work > pkg install generic-pkg
Installed generic-pkg@1.2.0이 경우 package.json에는 해석된 npm 버전 범위가 저장됩니다.
{
"dependencies": {
"generic-pkg": "^1.2.0"
}
}GitHub 저장소 패키지
패키지 이름이 github.com/<org>/<repo> 형식이면 GitHub 저장소 내용을 직접 내려받아 설치합니다.
지원 형식은 다음과 같습니다.
github.com/<org>/<repo>github.com/<org>/<repo>@<tag>github.com/<org>/<repo>#tag=<tag>github.com/<org>/<repo>#branch=<branch>
동작 방식은 다음과 같습니다.
@<tag>또는#tag=<tag>를 지정하면 해당 tag를 사용합니다.#branch=<branch>를 지정하면 tag 존재 여부와 무관하게 해당 branch를 사용합니다.- tag를 지정하지 않았고 저장소에 tag가 있으면 GitHub tags API가 반환한 최신 tag를 사용합니다.
- tag를 지정하지 않았고 저장소에 tag가 없으면 저장소의
default_branch를 사용합니다.
사용 예시: 최신 tag 설치
/work > pkg install github.com/acme/demo
Installed github.com/acme/demo#tag=v1.1.0사용 예시: 특정 tag 설치
/work > pkg install github.com/acme/demo@v1.0.0
Installed github.com/acme/demo#tag=v1.0.0명시적인 ref 구문도 사용할 수 있습니다.
/work > pkg install github.com/acme/demo#tag=v1.0.0
Installed github.com/acme/demo#tag=v1.0.0사용 예시: 특정 branch 설치
/work > pkg install github.com/acme/demo#branch=develop
Installed github.com/acme/demo#branch=develop사용 예시: default branch fallback
저장소에 tag가 하나도 없으면 default branch를 사용합니다.
/work > pkg install github.com/acme/notags
Installed github.com/acme/notags#branch=main설치 위치
설치된 패키지는 선택된 node_modules 디렉터리 아래에 복사됩니다.
예를 들면 다음과 같습니다.
generic-pkg->node_modules/generic-pkggithub.com/acme/demo->node_modules/github.com/acme/demo
GitHub 저장소 패키지도 예외 없이 node_modules 아래에 설치됩니다.
pkg install -g를 사용하면 이 위치는 /work/node_modules가 됩니다.
설치한 패키지의 package.json에 bin이 있으면 pkg는 node_modules/.bin 아래에 wrapper를 생성합니다.
wrapper 이름은 설치한 패키지 manifest의 bin 설정을 그대로 따릅니다.
지원하는 bin 형식은 다음 두 가지입니다.
- 문자열 형식:
"bin": "main.js" - 객체 형식:
"bin": { "demo": "demo.js" }
bin이 문자열이면 pkg는 패키지 이름으로부터 wrapper 이름을 결정합니다.
예를 들어 github.com/acme/demo는 demo.js를 생성합니다.
bin이 객체이면 각 key가 wrapper 이름이 됩니다.
wrapper 이름에는 영문자, 숫자, ., _, -만 사용할 수 있습니다.
예를 들어 설치한 패키지 manifest가 다음과 같다면,
{
"name": "github.com/acme/demo",
"bin": {
"demo": "demo.js"
}
}node_modules/.bin/demo.js가 생성됩니다. 생성된 wrapper는 설치된 패키지 디렉터리로 작업 디렉터리를 옮긴 뒤, bin에 지정된 대상을 실행합니다.
따라서 bin 대상은 설치된 패키지 루트 기준으로 유효한 경로여야 합니다.
wrapper 뒤에 전달한 추가 인자는 해당 대상에 그대로 전달됩니다.
생성된 .bin wrapper 실행
pkg run은 설치된 패키지의 .bin wrapper를 실행하지 않습니다.
pkg run은 현재 프로젝트의 package.json scripts만 실행합니다.
셸 환경에는 /work/node_modules/.bin 과 ./node_modules/.bin 이 PATH에 포함되어 있습니다.
따라서 설치된 패키지 실행 파일은 보통 이름만으로 바로 실행할 수 있습니다.
설치된 패키지 실행 파일을 사용하려면 셸에서 생성된 wrapper를 실행하면 됩니다. 예시는 다음과 같습니다.
/work > demo.js --help
/work > demo.js import sample.csv필요하면 wrapper 경로를 직접 지정해서 실행할 수도 있습니다.
/work > ./node_modules/.bin/demo.js --help같은 wrapper 이름이 이미 있으면 설치는 계속 진행되고 경고 메시지를 출력하며, 충돌한 wrapper만 생성하지 않습니다. 즉 패키지 설치 자체는 성공하지만, 해당 실행 이름만 만들지 않습니다.
충돌한 파일이 다른 설치 패키지가 만든 wrapper면 경고에 owner package 이름이 포함됩니다.
반대로 pkg가 관리하지 않는 기존 파일이면 단순히 existing wrapper로 보고합니다.
lock file 동작
일반 프로젝트 설치에서는 pkg가 재현 가능한 설치를 위해 package-lock.json에 해석된 소스를 기록합니다.
GitHub 패키지는 tag 기반인지 branch 기반인지까지 함께 저장합니다.
예시는 다음과 같습니다.
github.com/acme/demo#tag=v1.1.0github.com/acme/notags#branch=main
lock file이 있으면 pkg install은 새 ref를 다시 해석하지 않고 lock에 기록된 GitHub ref를 재사용합니다.
에러 보고
GitHub ref를 결정하지 못하면 pkg는 두 단계의 실패 원인을 함께 보여줍니다.
예를 들어 tags 조회 실패와 default branch 조회 실패를 한 문장에 묶어서 보고합니다.
pkg copy
GitHub 저장소 패키지를 node_modules 아래에 설치하는 대신, 요청한 대상 디렉터리로 직접 복사합니다.
프로젝트 파일을 복사한 뒤에는 복사된 프로젝트 루트와, 존재하는 경우 cgi-bin 에서 의존성을 설치합니다.
사용 형식
pkg copy [options] <source> <dest>옵션
-f, --force대상 디렉터리가 이미 존재하고 비어 있지 않아도 계속 진행합니다.-h, --help도움말을 표시합니다.
source 는 pkg install 이 지원하는 것과 동일한 GitHub 저장소 구문을 사용해야 합니다.
지원 형식은 다음과 같습니다.
github.com/<org>/<repo>github.com/<org>/<repo>@<tag>github.com/<org>/<repo>#tag=<tag>github.com/<org>/<repo>#branch=<branch>
dest 는 현재 작업 디렉터리를 기준으로 해석하는 파일 시스템 경로입니다.
대상 디렉터리가 없으면 pkg copy 가 생성합니다.
대상 디렉터리가 이미 존재하고 비어 있지 않으면 --force 가 없는 한 실패합니다.
복사 동작
pkg copy 는 GitHub ref 해석 규칙을 pkg install 과 동일하게 재사용합니다.
즉, 명시적인 tag 또는 branch 가 있으면 그것을 사용하고, 없으면 최신 tag 를 해석하며, tag 가 없으면 저장소의 default_branch 를 사용합니다.
복사된 저장소 내용은 <dest> 아래에 직접 기록됩니다.
pkg install 과 달리 GitHub 프로젝트를 node_modules/github.com/... 아래에 두지 않습니다.
원본 디렉터리 구조는 대상 디렉터리 아래에서 그대로 유지됩니다.
복사 단계가 끝나면 pkg copy 는 다음 프로젝트 루트를 검사하고, pkg install 과 동일한 설치 로직과 lock file 동작으로 의존성을 설치합니다.
<dest>/package.json이 있으면<dest><dest>/cgi-bin/package.json이 있으면<dest>/cgi-bin
따라서 복사된 각 프로젝트 루트는 자신의 node_modules, package-lock.json 을 별도로 유지합니다.
사용 예시
/work > pkg copy github.com/acme/helloapp public/hello
Copying github.com/acme/helloapp#branch=main to /work/public/hello
Installing dependencies in /work/public/hello
Installing dependencies in /work/public/hello/cgi-bin이 명령을 실행하면 다음과 같습니다.
- 저장소 파일이
/work/public/hello아래로 복사됩니다. /work/public/hello/package.json의 의존성이/work/public/hello/node_modules에 설치됩니다./work/public/hello/cgi-bin/package.json이 있으면 그 의존성이/work/public/hello/cgi-bin/node_modules에 설치됩니다.
특정 경로에 프로젝트 트리를 그대로 두고 싶지만, GitHub ref 해석과 복사된 프로젝트의 의존성 설치는 pkg 에 맡기고 싶을 때 pkg copy 를 사용하면 됩니다.
pkg run
package.json의 scripts를 실행합니다.
사용 형식
pkg run [options] <key> [...args]옵션
-C, --dir <dir>현재 작업 디렉터리 대신 지정한 프로젝트 디렉터리를 사용합니다.-g, --global--dir를 무시하고/work/node_modules에서 패키지를 제거합니다.-h, --help도움말을 표시합니다.
pkg run은 스크립트를 실행하기 전에 현재 작업 디렉터리를 선택한 프로젝트 디렉터리로 변경합니다.
따라서 ./main.js 같은 상대 경로 명령은 패키지 디렉터리를 기준으로 해석됩니다.
사용 예시
다음 manifest가 있다고 가정하면,
{
"scripts": {
"start": "./main.js --mode prod"
}
}다음과 같이 실행할 수 있습니다.
/work > pkg run start추가 인자는 스크립트 명령행 뒤에 이어 붙습니다.
/work > pkg run start --verbose최종적으로 실행되는 명령행은 다음과 같습니다.
./main.js --mode prod --verbosepkg uninstall
의존성과 생성된 wrapper를 함께 제거합니다.
사용 형식
pkg uninstall [options] <name>옵션
-C, --dir <dir>현재 작업 디렉터리 대신 지정한 프로젝트 디렉터리를 사용합니다.-h, --help도움말을 표시합니다.
pkg uninstall은 다음 항목을 정리합니다.
package.json의 dependency 항목- 설치한 패키지에 속한
node_modules/.binwrapper - 설치된 패키지 디렉터리
- 필요 시
package-lock.json
pkg install -g로 설치한 패키지를 제거하려면 pkg uninstall -g를 사용합니다.
/work > pkg uninstall -g github.com/acme/demo
Removed github.com/acme/demo설치 시 alias 충돌 때문에 wrapper 생성이 건너뛰어졌다면 삭제할 wrapper가 없을 수 있습니다.
또한 pkg uninstall은 pkg가 관리하지 않는 사용자가 만든 node_modules/.bin 파일은 삭제하지 않습니다.
사용 예시
/work > pkg uninstall github.com/acme/demo
Removed github.com/acme/demo일반적인 작업 순서
/work > pkg init demo-app
/work > pkg install github.com/acme/demo
/work > pkg install generic-pkg
/work > pkg run start참고
install을 패키지 이름 없이 실행하거나run을 실행하려면 유효한package.json이 필요합니다.pkg run은 POSIX shell이 아니라 JSH 명령 해석을 통해 스크립트 라인을 실행합니다.- 프로젝트 내부 실행 파일은
./tool.js같은 상대 경로로 정의하는 것을 권장합니다. - 패키지 개발자는 생성된 wrapper가 설치 패키지 디렉터리에서 실행된다는 점을 기준으로
./bin/demo.js같은 상대bin경로를 사용하는 편이 안전합니다. - 패키지 개발자는 실행 이름을 명시적으로 정하고 싶다면 객체 형식
bin을, 패키지 이름을 그대로 실행 이름으로 쓰고 싶다면 문자열 형식bin을 사용하면 됩니다. - GitHub 저장소 설치는 내려받은 저장소 내용 안에 유효한
package.json이 있어야 합니다.