npm-scripts
How npm handles the "scripts" field
Description
아래와 같은 package.json 파일에서 "scripts" 프로퍼티를 사용할 수 있습니다.
- prepublish: 팩키지를 퍼블리쉬하기전에 실행됩니다. (또한 로컬에서 다른 인자 없이 npm install를 실행할 때에도 적용됩니다.)
- publish, postpublish: 팩키지를 퍼블리쉬한 후에 실행됩니다.
- preinstall: 팩키지를 인스톨하기 전에 실행됩니다.
- install, postinstall: 팩키지를 인스톨한 후에 실행됩니다.
- preuninstall, uninstall: 팩키지를 언인스톨하기 전에 실행됩니다.
- postuninstall: 팩키지를 언이스톨한 후에 실행됩니다.
- preversion, version: Run BEFORE bump the package version.
- postversion: Run AFTER bump the package version.
- pretest, test, posttest: Run by the npm test command.
- prestop, stop, poststop: Run by the npm stop command.
- prestart, start, poststart: Run by the npm start command.
- prerestart, restart, postrestart: Run by the npm restart command. 주의: npm restart 시에 restart 스크립트를 지정하지 않으면 stop과 start 스크립트가 실행됩니다.
일반적인 활용
팩키지를 사용하기 전에 팩키지를 어떤 작업을 수행해야하는데 이 작업이 운영 시스템이나 대상 시스템의 아키텍쳐에 의존적이지 않다면 prepublish 스크립트를 사용합니다. 예를 들어 다음과 같은 경우입니다.
- CoffeeScript 소스코드를 JavaScript로 컴파일
- JavaScript 소스코드를 minified된 버전으로 생성
- 팩키지에서 사용해야하는 리모트 리소스를 받아오기
이런 작업을 prepublish에 기술하게 되면 변경이 발생할 때 이 부분만 수정하면 되므로 복잡도를 낮출 수 있습니다.
- coffee-script를 devDependency에만 의존성을 부여하므로 팩키지의 사용자는 추가로 설치할 필요가 없습니다.
- minifier를 팩키지에 포함할 필요가 없으므로 팩키지의 크기를 줄일 수 있습니다.
- 사용자가 curl이나 wget을 실행할 필요가 없습니다.
디폴트 값
팩키지의 내용에 따라 npm은 몇 가지 디폴트 스크립트 값을 가지게 됩니다.
- "start": "node server.js"
만약 팩키지의 최상위 경로에 server.js가 존재하면 npm은 start 명령어로 start server.js를 디폴트로 설정됩니다.
- "install": "node-gyp rebuild"
만약 팩키지 최상위 경로에 binding.gyp 파일이 존재하면 npm은 install 명령어로 node-gyp를 사용하여 컴파일하게 됩니다.
사용자
npm을 root 권한으로 실행하면 사용자 계정의 uid나 user 설정에 지정된 uid로 변경하게 되는데 이 값은 디폴트로 nobody입니다. root 권한으로 스크립트를 실행하려면 unsafe-perm 플래그를 설정해야합니다.
환경변수
팩키지 스크립트는 npm의 설정과 프로세스의 현재 상태에 따라 다양한 정보들이 환경 변수로 받아 올 수 있습니다.
path
실행 가능한 스크립트를 정의하는 모듈에 따라서 이들 실행 파일들을 실행할 수 있도록 PATH 에 추가됩니다. 따라서 만약 package.json에 다음과 같이 설저되어 있다면
{ "name" : "foo"
, "dependencies" : { "bar" : "0.1.x" }
, "scripts": { "start" : "bar ./test" } }
npm install을 통해서 node_modules/.bin 디렉터리에 익스포트된 bar 스키립트를 실행하기 위해서 npm start를 실행할 수 있습니다.
package.json vars
package.json 필드들은 npm_package_ 프리픽스를 추적합니다. 예를 들어 package.json 파일 내에 {"name":"foo", "version":"1.2.5"}
로 되어 있다면, 팩키지 스크립트에서는 npm_package_name 환경 변수를 통해서 foot값을 참조할 수 있으며 npm_package_version은 "1.2.5"로 설정되게 됩니다.
configuration
설정 파라미터들은 npm_config_로 시작하는 환경 변수로 들어갑니다. 예를 들어 root 설정은 npm_config_root 환경 변수를 통해서 확인할 수 있습니다.
package.json의 config 객체
<name>[@version]:
{ "name" : "foo"
, "config" : { "port" : "8080" }
, "scripts" : { "start" : "node server.js" } }
server.js가 아래와 같다면
http.createServer(...).listen(process.env.npm_package_config_port)
사용자는 아래와 같이 함으로써 변경할 수 있습니다.
npm config set foo:port 80
current lifecycle event
마지막으로 npm_lifecycle_event 환경 변수는 실행 중인 cycle 단계에 따라 변경됩니다. 따라서 하나의 스크립트에서 현재 실행되는 상태에 따라 다른 일을 하도록 설정할 수 있습니다.
package.json에 ``으로 되어 있다면 스크립트 내에서는 아래와 같이 보입니다.
process.env.npm_package_scripts_install === "foo.js"
EXAMPLES
{ "scripts" :
{ "install" : "scripts/install.js"
, "postinstall" : "scripts/install.js"
, "uninstall" : "scripts/uninstall.js"
}
}
{ "scripts" :
{ "preinstall" : "./configure"
, "install" : "make && make install"
, "test" : "make test"
}
}
EXITING
스크립트는 sh에 파라미터로 전달되어 실행됩니다.
만약 스크립트가 0이 아닌 코드 값으로 종료되면, 프로세스가 강제 종료(abort)됩니다.
스크립트 자체는 javascript 또는 nodejs 프로그램일 필요는 없으며 그냥 실행 가능한 파일이면 됩니다.
HOOK SCRIPTS
모든 팩키지에 대해서 특정 라이프사이클 이벤트에 특정 스크립트를 실행하고 싶다면 후크 스크립트를 사용할 수 있습니다.
실행가능한 파일을 node_modules/.hooks/{eventname}
에 두면, 모든 팩키지에 대해서 해당 라이프 사이클로 진입할 때 실행됩니다.
후크 스크립트는 package.json 스크립트가 실행되는 것과 동일한 방법으로 별도의 자식 프로세스로 위에서 설명한 환경상에서 실행됩니다.
BEST PRACTICE
- Don't exit with a non-zero error code unless you really mean it. Except for uninstall scripts, this will cause the npm action to fail, and potentially be rolled back. If the failure is minor or only will prevent some optional features, then it's better to just print a warning and exit successfully.
- Try not to use scripts to do what npm can do for you. Read through package.json to see all the things that you can specify and enable by simply describing your package appropriately. In general, this will lead to a more robust and consistent state.
- Inspect the env to determine where to put things. For instance, if the npm_config_binroot environment variable is set to /home/user/bin, then don't try to install executables into /usr/local/bin. The user probably set it up that way for a reason.
- Don't prefix your script commands with "sudo". If root permissions are required for some reason, then it'll fail with that error, and the user will sudo the npm command in question.
- Don't use install. Use a .gyp file for compilation, and prepublish for anything else. You should almost never have to explicitly set a preinstall or install script. If you are doing this, please consider if there is another option. The only valid use of install or preinstall scripts is for compilation which must be done on the target architecture.