부끄럽지만 요녀석을 한번도 제대로 정리해본적은 없다.
간간히 궁금해서 1~2년마다 찾아보긴 했지만 그때 잠깐 기억 해놓고 다시 안보기 일쑤.
그나마 아는 필드들은 scripts, dependencies(+dev), name, author, version 정도.
그래서 이번에 제대로 정리해보려고 한다.
공식 docs 가 짱이다.
npm 은 node package manager 를 뜻한다.
package.json 은 이 npm으로 관리되는 하나의 완전한 패키지에 대한 메타 정보를 다룬다.
참고.
npmjs.com 에서 package.json 에 기재한 정보는 다음과 같이 노출된다!
그럼 필드 들을 알아보러 떠나보즈아~😆
우리가 만들고자 하는 패키지에 부여할 이름이다.
패키지를 게시(publish) 하려면 최소 필드가 name과 version 이다.
@{scope}/{name} 같이 스코프를 지원한다.패키지의 버전이다.
node-semver에 의해 파싱이 가능해야한다. (semver 를 따르면된다)패키지에 대한 설명이다.
npm search 로 검색할 수 있게 적절하게 써주는 게 좋다.relay - Relay offers three higher order functions to control flow of “node.js-style” functions – chain, combine and parallel.@nestjs/core : Nest - modern, fast, powerful node.js web framework (@core)키워드 문자열 배열이다. 이 역시 npm search 의 검색 대상이 되기에 잘 나열해주면 좋다.
프로젝트의 홈페이지가 있다면 여기에 써주자.
보통 docs 나 github repo(readme) 를 써놓는다.
@egjs/react-flicking: https://naver.github.io/egjs-flicking객체로 버그 이슈에 대한 문의 채널을 써놓는다.
{
"url": "https://github.com/owner/project/issues",
"email": "project@hostname.com"
}
패키지에 기여한 1인이나, n명을 써놓는다.
개인 한명은 다음과 같은 오브젝트로 나타낸다.
{
"name": "Barney Rubble",
"email": "b@rubble.com",
"url": "http://barnyrubble.tumblr.com/"
}
여기서는 이름만 필수 필드다.
재밌는 필드다. 패키지 개발에 자금 지원에 대한 채널들을 써놓을 수 있다.
패키지의 엔트리 포인트를 가리킨다.
여기서 가리키는 파일의 exports 객체를 패키지 사용처에서 require 할때 가져온다. 패키지 루트에서 상대경로로 정의되어야 한다.
e.g.
// main 으로 가리키는 어떤 .js 파일
module.exports = {
foo: 1,
}
// 패키지 사용처
const a = require('my-package')
a // { foo: 1 }
주로 cli 용 패키지가 이 필드를 사용하는데 실행파일을 가리킨다.
패키지를 글로벌로 설치하면 bin 필드에 정의한 필드명으로 커맨드를 실행할 수 있다.
전역으로 설치시(npm i -g) /user/local/bin 에 정의한 필드명으로 symbolic link 가 만들어진다.
e.g.
{ "bin": { "myapp": "./cli.js" } } 일 경우 /user/local/bin/myapp 에 만들어진 심볼릭 링크가 cli.js 을 가리키게 된다.
덕분에 우리는 myapp 커맨드를 쓸 수 있다.
당장 로컬에서 ls /usr/local/bin 을 해보자. 많은 cli 용 패키지들이 보인다.
주의! bin 으로 가리키는 파일은 반드시 #!/usr/bin/env node 로 시작되어야 node 환경으로 시작한다.
cli man 프로그램이 찾을 수 있게 해준다. 설명해주는 파일도 지정가능!
단일 파일 경로로 값을 넣으면 man <package-name>으로 열린다.
참고
실습시 실험해봤는데 정상 동작하지 않았따 😢
groff 문법을 지켜서 gpt 에게 작성하게 했는디...
원인 찾는 것은 본 글의 진행을 방해할 것 같아 stop!
코드 레포지토리를 써준다.
{
"repository": {
"type": "git",
"url": "https://github.com/npm/cli.git"
}
}
우리가 쓰고 싶은 cli 커맨드와 alias 를 지정할 수 있다.
몇가지 라이프사이클 이벤트에 동작하는 필드명들도 있다. 참고
(이거 아는 사람 몇이나 될까?) scripts 에서 사용할 수 있는 환경변수를 셋업해둘 수 있다.
예시
{ "config": { "PORT": "8080" }, "scripts": { "test": "echo $npm_package_config_PORT" } }이후
npm run test시8080이 출력된다!
의존성 패키지들을 패키지이름과 버전 범위 key-value로 이루어진 객체로 명시한다.
버점 범위로 url 을 쓸수도 있다!
{"package-name": "http://asdf.com/asdf.tar.gz"}버전 범위로 local path 도 쓸 수 있다! (당연히 게시할 패키지엔 사용해선 안된다 😉)
{"package-name": "../foo/bar"}우리 패키지를 다운받을 사용자에게 포함하고 싶지 않은 패키지들은 여기에 명시해두면 된다. 즉, 패키지 사용자들은 dependencies 에 명시된 의존성들만 설치하게 된다.
host 도구나 라이브러리와의 호환성을 표현하고 싶은데, host 패키지에 의존성을 나타내고 싶지 않거나, 의존하지 않을 경우 쓸 수 있다.
주로 플러그인 패키지들이 이 필드로 host 패키지를 나타낸다.
만약 host 패키지가 설치되어있지 않은 상태로 install 하게 되면
e.g.
{
"name": "tea-latte",
"version": "1.3.5",
"peerDependencies": { "tea": "2.x" }
}
이를 테면 tea-latte 패키지가 위와 같이 명시되어있다면
host 패키지가 2.x 일 경우 문제가 없다.
참고. @nestjs/swagger 패키지의 peerDependencies 는 다음과 같다.
{
"peerDependencies": {
"@fastify/static": "^6.0.0",
"@nestjs/common": "^9.0.0 || ^10.0.0",
"@nestjs/core": "^9.0.0 || ^10.0.0",
"class-transformer": "*",
"class-validator": "*",
"reflect-metadata": "^0.1.12"
}
}
주의! peerDependencies 의 버전 레인지를 넉넉하게 잡아두자.
다른 플러그인 설치시 요구 버전이 달라 충돌이 날 수 있다.
의존하는 node 버전을 명시한다.
{
"engines": {
"node": ">=0.10.3 <15"
}
}
의존적인 os 도 지정할 수 있음!
{
"os": ["darwin", "linux"]
}
의존적인 cpu 아키텍쳐도 지정할 수 있다.
{
"cpu": ["x64", "ia32"]
}
true 일 경우 npm 이 publish 를 막아준다. (비게시 목적의 package 일 경우 씀)
monorepo 에서 하위 패키지들은 게시대상이지만, root 는 게시대상이 아닐 경우도 쓴다.
e.g. next.js
publish-time 에 쓸 설정 값들. 자세히
패키지를 인스톨하는 클라이언트 측에서 심볼릭 링크로 설치해야할 워크스페이스내 패키지가 있으면 정의해준다.
즉 이곳에 정의해놓은 패키지들은 레지스트리를 타지 않고, 패키지 내에서 레졸루션 됨.
빠짐 없이 다 알아보았다.
이제는 package.json 보면서 음미 해보자~
호오 arm 아키텍쳐의 mac에서 돌아가는 node@^16 에서 써야하는 패키지군?
호스트 패키지가 있네?
오 이건 전역으로 설치할 경우 커맨드 라인에서 쓸 수 있겠군!
start 스크립시 여기에 명시된 환경변수가 주입되겠군!
😘
추가.
yarn 패키지 매니져만 다루는 필드다. 참고
특정 패키지의 버전 resolution을 강제로 고정시킴.
e.g.
다음은 모노레포 내 리액트 버전을 18.2.0 이상으로 고정시킨 것.
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*"],
"resolutions": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"engines": {
"node": ">=10"
},
"license": "ISC"
}