package.json 어디까지 아니?

공명·2023년 12월 18일

부끄럽지만 요녀석을 한번도 제대로 정리해본적은 없다.
간간히 궁금해서 1~2년마다 찾아보긴 했지만 그때 잠깐 기억 해놓고 다시 안보기 일쑤.
그나마 아는 필드들은 scripts, dependencies(+dev), name, author, version 정도.
그래서 이번에 제대로 정리해보려고 한다.

공식 docs 가 짱이다.

npm 은 node package manager 를 뜻한다.
package.json 은 이 npm으로 관리되는 하나의 완전한 패키지에 대한 메타 정보를 다룬다.

참고.
npmjs.com 에서 package.json 에 기재한 정보는 다음과 같이 노출된다!

그럼 필드 들을 알아보러 떠나보즈아~😆

name

우리가 만들고자 하는 패키지에 부여할 이름이다.
패키지를 게시(publish) 하려면 최소 필드가 name과 version 이다.

  • js 나 node 를 넣지 말자, 우리는 이미 node 패키지를 만들고 있고 이는 js 를 쓴다는 것이기 때문에
  • 당연하게도 게시할 생각이면 이미 게시된 이름과 충돌되지 않게 해야한다.
  • 자주 사용되는 이름이 많을 것이므로 @{scope}/{name} 같이 스코프를 지원한다.

version

패키지의 버전이다.

  • node-semver에 의해 파싱이 가능해야한다. (semver 를 따르면된다)

description

패키지에 대한 설명이다.

  • 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)

keywords

키워드 문자열 배열이다. 이 역시 npm search 의 검색 대상이 되기에 잘 나열해주면 좋다.

homepage

프로젝트의 홈페이지가 있다면 여기에 써주자.

보통 docs 나 github repo(readme) 를 써놓는다.

bugs

객체로 버그 이슈에 대한 문의 채널을 써놓는다.

{
  "url": "https://github.com/owner/project/issues",
  "email": "project@hostname.com"
}

author, contributors

패키지에 기여한 1인이나, n명을 써놓는다.

개인 한명은 다음과 같은 오브젝트로 나타낸다.

{
  "name": "Barney Rubble",
  "email": "b@rubble.com",
  "url": "http://barnyrubble.tumblr.com/"
}

여기서는 이름만 필수 필드다.

funding

재밌는 필드다. 패키지 개발에 자금 지원에 대한 채널들을 써놓을 수 있다.

main

패키지의 엔트리 포인트를 가리킨다.

여기서 가리키는 파일의 exports 객체를 패키지 사용처에서 require 할때 가져온다. 패키지 루트에서 상대경로로 정의되어야 한다.

e.g.

// main 으로 가리키는 어떤 .js 파일
module.exports = {
  foo: 1,
}

// 패키지 사용처
const a = require('my-package')
a // { foo: 1 }

bin

주로 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 환경으로 시작한다.

man

cli man 프로그램이 찾을 수 있게 해준다. 설명해주는 파일도 지정가능!
단일 파일 경로로 값을 넣으면 man <package-name>으로 열린다.

참고
실습시 실험해봤는데 정상 동작하지 않았따 😢
groff 문법을 지켜서 gpt 에게 작성하게 했는디...
원인 찾는 것은 본 글의 진행을 방해할 것 같아 stop!

repository

코드 레포지토리를 써준다.

{
  "repository": {
    "type": "git",
    "url": "https://github.com/npm/cli.git"
  }
}

scripts

우리가 쓰고 싶은 cli 커맨드와 alias 를 지정할 수 있다.
몇가지 라이프사이클 이벤트에 동작하는 필드명들도 있다. 참고

config

(이거 아는 사람 몇이나 될까?) scripts 에서 사용할 수 있는 환경변수를 셋업해둘 수 있다.

예시

{
  "config": { "PORT": "8080" },
  "scripts": { "test": "echo $npm_package_config_PORT" }
}

이후 npm run test8080 이 출력된다!

dependencies

의존성 패키지들을 패키지이름과 버전 범위 key-value로 이루어진 객체로 명시한다.
버점 범위로 url 을 쓸수도 있다!

  • e.g. {"package-name": "http://asdf.com/asdf.tar.gz"}

버전 범위로 local path 도 쓸 수 있다! (당연히 게시할 패키지엔 사용해선 안된다 😉)

  • e.g. {"package-name": "../foo/bar"}

devDependencies

우리 패키지를 다운받을 사용자에게 포함하고 싶지 않은 패키지들은 여기에 명시해두면 된다. 즉, 패키지 사용자들은 dependencies 에 명시된 의존성들만 설치하게 된다.

peerDependencies

host 도구나 라이브러리와의 호환성을 표현하고 싶은데, host 패키지에 의존성을 나타내고 싶지 않거나, 의존하지 않을 경우 쓸 수 있다.
주로 플러그인 패키지들이 이 필드로 host 패키지를 나타낸다.

만약 host 패키지가 설치되어있지 않은 상태로 install 하게 되면

  • npm 3-6 : 경고(warn)해준다.
  • npm 7~ : peerDependecies 에 명시된 패키지도 설치해준다.

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 의 버전 레인지를 넉넉하게 잡아두자.
다른 플러그인 설치시 요구 버전이 달라 충돌이 날 수 있다.

기타 dependencies

  • peerDependenciesMeta : 피어가 설치 되지 않았을 경우 자동 설치가 안되게 옵셔널 선언가능.
  • bundledDependencies : 패키지를 게시할 때 번들로 제공될 패키지들을 정의.
  • optionalDependencies : 선택적으로 의존하는 패키지 선언. optionalDependencies 로 의존하는 패키지들이 설치 되어있지 않아도 설치시 문제가 없다. 다만 옵셔널로 의존하는 패키지가 없을 경우 폴백은 패키지 내에서 해결해야 한다.

engines

의존하는 node 버전을 명시한다.

{
  "engines": {
    "node": ">=0.10.3 <15"
  }
}

os

의존적인 os 도 지정할 수 있음!

{
  "os": ["darwin", "linux"]
}

cpu

의존적인 cpu 아키텍쳐도 지정할 수 있다.

{
  "cpu": ["x64", "ia32"]
}

private

true 일 경우 npm 이 publish 를 막아준다. (비게시 목적의 package 일 경우 씀)
monorepo 에서 하위 패키지들은 게시대상이지만, root 는 게시대상이 아닐 경우도 쓴다.
e.g. next.js

publishConfig

publish-time 에 쓸 설정 값들. 자세히

workspaces

패키지를 인스톨하는 클라이언트 측에서 심볼릭 링크로 설치해야할 워크스페이스내 패키지가 있으면 정의해준다.
즉 이곳에 정의해놓은 패키지들은 레지스트리를 타지 않고, 패키지 내에서 레졸루션 됨.

빠짐 없이 다 알아보았다.
이제는 package.json 보면서 음미 해보자~

호오 arm 아키텍쳐의 mac에서 돌아가는 node@^16 에서 써야하는 패키지군?
호스트 패키지가 있네?
오 이건 전역으로 설치할 경우 커맨드 라인에서 쓸 수 있겠군!
start 스크립시 여기에 명시된 환경변수가 주입되겠군!

😘


추가.

resolutions

yarn 패키지 매니져만 다루는 필드다. 참고
특정 패키지의 버전 resolution을 강제로 고정시킴.

e.g.

  • a 패키지를 쓰는데 a 가 의존하는 b 패키지를 v1 으로 고정하고 싶다.
  • 모노레포 내 a, b, c 에서 쓰는 react 패키지 버전을 통일하고 싶다.

다음은 모노레포 내 리액트 버전을 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"
}
profile
더 나은 추상화로 더 아름답게

0개의 댓글