[Nodejs] package.json

Lian Kim·2022년 9월 13일
2

새로운 프로젝트나 패키지를 만들 때 가장 먼저 하는 일은 npm 프로젝트로 초기화 해주는 명령어 npm init을 실헹하는 것이다. 이때 package.json 파일이 생성되는데 언뜻 봐도 프로젝트에 대한 정보를 담고 있는 중요한 파일처럼 보인다. package.json은 어떻게 사용되는 파일일까?





📌 package.json이란?

Node.js 프로젝트에서는 많은 패키지를 사용하게 되고 패키지의 버전도 빈번하게 업데이트 되므로, 프로젝트가 의존하고 있는 패키지를 일괄적으로 관리할 필요가 있다.

npm은 package.json 파일을 통해서 프로젝트의 정보와 패키지 의존성(dependency)을 관리한다. package.json 파일에는 이 프로그램을 실행시키기 위해 필요한 모듈들에 대한 정보와, 프로그램을 실행시키는 방법, 프로그램을 테스트하는 방법 등이 명시되어 있다.

package.json 파일을 이용하면 협업 시 동일한 개발 환경을 빠르게 구축할 수 있다는 장점이 있다.





📌 pacakge.json 파일 생성

프로젝트의 루트 디렉토리에서 npm init 명령어를 실행하면 package.json 파일이 생성된다.
-y 또는 --yes 옵션을 추가하면 기본 설정값으로 생성된다.

npm init

# 기본 설정값 적용
npm init -y
npm init --yes

npm init -y를 실행하면 아래와 같이 기본 설정값이 적용된 package.json 파일이 생성된다.

{
  "name": "test-for-studying",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}




📌 pacakge.json의 프로퍼티

각 프로퍼티는 JSON 형식의 key: value 형태로 구성된다.
name과 version을 통해서 각 패키지의 고유성을 판별하기 때문에, 배포될 패키지라면 이 두 프로퍼티가 가장 중요하다.


name

프로젝트의 이름.

{
  "name": "test-for-studying",
}

name을 정할 때는 몇 가지 규칙을 따라야 한다.

  • 214자 이하
  • .(점) 또는 _(언더스코어)로 시작 불가
  • 대문자 포함 불가
  • URL이나 디렉토리에 사용할 수 없는 문자 포함 불가 (name은 URL, 폴더 이름, command line의 인수가 되기 때문)
  • "js", "node" 포함 불가
  • 짧고 알아보기 쉬운 것으로 (require() 함수의 인수로 전달되기 때문)


version

프로젝트 버전.

{
  "version": "1.0.0",
}

패키지의 내용이 변경되면 version도 변경해줘야 한다.
version은 메이저 버전 번호, 마이너 버전 번호, 패치 버전 번호로 구성되며, node-semver로 파싱할 수 있어야 한다.

Semantic Versioning (semver)

버전 정보는 아래와 같이 유의적으로 구성되어 있다.

  1. 메이저 버전 번호: 하위 호환이 되지 않는 변경 사항
  2. 마이너 버전 번호: 하위 호환이 되는 변경 사항
  3. 패치 버전 번호: 간단한 버그 수정

버전 정보 앞에 기호를 부여하면 업데이트 범위를 지정할 수 있다.

표기법설명
version명시된 version과 일치
>version명시된 version보다 높은 버전
>=version명시된 version과 같거나 높은 버전
<version명시된 version보다 낮은 버전
<=version명시된 version과 같거나 낮은 버전
~version명시된 version과 근사한 버전 (패치 버전 범위 내)
^version명시된 version과 호환되는 버전 (마이너 버전 범위 내)

~(틸드): 패치 버전 범위 내에서 업데이트 (ex. ~0.1.1: 0.1.1 <= version < 0.2.0)
^(캐럿): 마이너 버전 범위 내에서 업데이트 (ex. ^1.0.2: 1.0.2 <= version < 2.0.0)



description

프로젝트 설명.

{
  "description": "An example module to study the usage of package.json",
}

문자열로 작성한다.
npm search로 검색된 리스트에 표시되기 때문에 사람들이 패키지를 발견하는데 도움이 된다.



keywords

프로젝트 검색에 참조되는 키워드.

{
  "keywords": [
    "example",
    "study",
  ],
}

배열 안에 문자열로 작성한다.
npm search로 검색된 리스트에 표시되기 때문에 사람들이 패키지를 발견하는데 도움이 된다.



license

라이센스 명시.

{
  "license": "ISC"
}

프로젝트를 배포하는 경우 라이센스가 일부 사용자의 소프트웨어 사용을 제한할 수 있기 때문에 매우 중요하다. 명확한 라이센스를 사용하면 어떤 조건에서 사용할 수 있는지 명확하게 정의할 수 있다. 일반적으로 라이센스 식별자 코드("MIT", "ISC"와 같은 문자열)로 작성한다.

다른 사용자에게 사용 권한을 부여하지 않으려면 아래와 같이 명시한다.

{
  "license": "UNLICENSED",
}

private 프로퍼티를 true로 설정하면 비공개 repository가 배포되지 않도록 미연에 방지할 수 있다.



author

프로젝트 작성자 정보.

{
	"author": {
		"name": "Lian Kim",
		"email": "5@gmail.com",
		"url": "https://velog.io/@liankim"
	},
}

한 사람만 지정할 수 있으며, name은 필수, email과 url은 선택이다.

"name <email> (url)" 형식을 사용하면 문자열 하나로 기술할 수도 있다.
아래와 같이 형식을 지켜 하나의 문자열로 묶으면 npm이 파싱해준다.

{
	"author": "Lian Kim <liankim@example.com> (https://velog.io/@liankim)"
}

또한 npm은 author 프로퍼티를 바탕으로 최상위 "maintainers" 필드에 npm user info를 설정한다.



contributors

프로젝트 기여자 정보.

{
  "contributors": [
    {
      "name": "Leah Kim",
   	  "email": "leahkim@example.com"
  	},
    {
      "name": "Nayoung Kim",
   	  "email": "nayoungkim@example.com"
  	},
  ],
}

배열 안에 여러 사람을 지정할 수 있다.



main

프로젝트의 시작점이 되는 모듈 지정 (미지정 시 프로젝트의 루트에 있는 index.js가 디폴트)

{
  "main": "index.js",
}

예를 들어, "foo"라는 패키지를 설치한 사용자가 require("foo")를 실행하면, main으로 지정된 모듈의 exports 객체가 반환된다.



repository

프로젝트의 소스 코드가 관리되는 저장소 위치.

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

소스 코드에 참여하고자 하는 사람들에게 도움이 될 수 있다.
url은 특별한 조작없이 VCS 프로그램에서 바로 다뤄질 수 있도록 오픈되어 있어야 하고, 프로젝트의 홈페이지 url을 명시하면 안된다.

package.json 파일이 루트 디렉토리가 아닌 다른 곳에 위치한다면 디렉토리를 명시해줘야 한다.

{
  "repository": {
    "type": "git",
    "url": "https://github.com/facebook/react.git",
    "directory": "packages/react-dom"
  },
}

GitHub, GitHubist, Bitbucket 또는 GitLab repository의 경우, npm install 사용 시와 동일하게 shorcut 구문을 사용할 수 있다.

{
  "repository": "npm/npm",
  "repository": "github:user/repo",
  "repository": "gist:11081aaa281",
  "repository": "bitbucket:user/repo",
  "repository": "gitlab:user/repo",
}


scripts

자주 실행하는 npm 명령어 등록.

{
  "scripts": {
     "start": "node index.js",
	 "test": "standard"
  },
}

key는 스크립트 이름이고, value는 실행할 사용자 정의 명령이다.
프로젝트에서 자주 실행해야 하는 명령어를 scripts에 작성해두면 npm run 명령어로 실행할 수 있다.

npm run <script-name>

default value

  • start: 만약 프로젝트의 루트에 server.js 파일이 존재하면, npm은 기본적으로 start 명령어를 사용했을 때 node server.js를 실행한다.
  • install: 만약 프로젝트의 루트에 binding.gyp 파일이 존재하면, npm은 기본적으로 install 명령어를 사용했을 때 node-gyp을 사용해서 컴파일한다.
{
	"scripts": {
		"start": "node server.js",
      	"install": "node-gyp rebuild",
	},
}


dependencies

프로덕션 환경에서(런타임 시) 필요한 패키지 관리.

{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
}

이 패키지를 실행하는 데 필요한 다른 패키지의 이름과 버전이 포함된다.
npm CLI를 사용하여 패키지를 설치하면 node_modules 디렉토리에 패키지가 저장되고, package.json 파일의 dependencies에 설치한 패키지의 이름과 버전이 명시된다.

애플리케이션을 설치할 때(npm install) dependencies를 참조하여 필요한 확장 모듈을 자동으로 설치한다.



devDependencies

개발 단계에서만 필요한 패키지 관리.

{
  "devDependencies": {
    "@babel/cli": "^7.18.10",
    "@babel/core": "^7.19.0",
    "@babel/preset-env": "^7.19.0",
    "@babel/preset-react": "^7.18.6",
    "babel-loader": "^8.2.5",
    "html-webpack-plugin": "^5.5.0",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.11.0"
  }
}

개발, 테스트 시에는 필요하지만 런타임 시에는 필요 없는 패키지들이 포함된다.

예를 들어, babel 같은 트랜스파일러나 webpack 같은 번들러의 경우 빌드 시에만 필요하기 때문에 설치할 때 -D(--save-dev) 옵션을 추가하여 devDependencies에서 관리한다.



private

{
	"private": true,
}

true로 설정하면 publish 명령을 거부하기 때문에 패키지가 배포되지 않는다.
비공개 repository가 실수로 배포되지 않도록 방지하는 방법이다.



engine

실행 가능한 노드 버전의 범위를 지정 (미지정 시 모든 버전이 해당됨)
사용자가 engine-strict config flag 미설정 시, 이 필드는 조언 용도로만 사용된다.

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

npm 버전도 지정할 수 있다.

{
  "engines": {
    "npm": "~1.0.20"
  }
}





📌 package-lock.json

package-lock.json 파일은 node_modules 트리나 package.json 파일이 수정되면 자동으로 생성되거나 업데이트되는 파일이다. package-lock.json 파일이 작성된 시점의 의존성 트리에 대한 정확한 정보를 가지고 있다.


사용 이유

package.json 파일에서는 패키지의 버전을 지정할 때 version range의 형태로 특정 버전이 아닌 버전의 범위를 지정한다(ex. ^18.2.0). 협업 시 같은 package.json을 사용해 동일한 개발환경을 구성하게 되는데, version range로 지정된 경우 업데이트된 버전이 설치되면서 에러를 발생시킬 수 있다. 이렇게 되면 같은 package.json을 사용하여 npm install을 진행하더라도 서로 다른 node_modules가 생성될 수 있다.

package.json의 dependencies

package-lock.json의 dependencies

package.json은 왜 버전을 범위로 지정할까?

만약 package.json에 패키지 버전을 정확히 명시하게 된다면, 프로젝트에서 사용하고 있는 패키지가 패치될 때마다 프로젝트의 package.json 파일에 명시된 버전도 수정해줘야 한다. version range를 명시함으로써 사용하는 모든 패키지들의 릴리즈를 항상 추적하고 수정해야 하는 번거로움을 해결할 수 있다.


npm install의 동작 변화

package-lock.json 파일이 존재하면, npm은 package.json 파일 대신 package-lock.json 파일을 사용하여 node_modules를 생성한다.


정리

의존성을 특정된 버전으로 동일하게 설치해줌으로써 동일한 개발환경 세팅을 도와주는, 협업 시 아주 중요한 파일이다. 따라서 package-lock.json 파일도 같이 커밋하는 것을 권장한다. (node_modules 없이 배포하는 경우 반드시 필요)






참고 자료
npm Docs package.json package-lock.json
PoimaWeb 모듈화와 npm
https://velog.io/@songyouhyun/Package.json과-Package-lock.json의-차이

0개의 댓글