알고 쓰자 package.json

야 package.json이 뭐냐?
어? 그거 npm 쓰려면 필요한 거, 설정파일..?

나름 수 개월에서 수 년을 사용했음에도 구체적으로 설명하지 못하겠더라…

기본적으로 package.json은 프로젝트에 대한 설정파일이라고 알고 있는게 전부다.

npm install을 통해 설치한 package에 대한 정보를 저장하는 용도로 알고 있는 정도?

node.js에서 사실상 표준이라고 볼 수 있는 npm을

잘 알고 쓸 수 있도록 필요한 package.json의 기본에 대해 알아본다



NPM(Node Package Manager)

먼저, npm이 무엇인가?

npm(Node Package Manager)은 node.js를 위한 패키지 매니저이자, node.js를 위한 오픈소스 생태계이다.

npm은 node.js에서 사용하는 모듈들을 패키지로 만들어 관리하고 배포하고 있다.

npm이 생겨난 이유?

모듈 패키징이 엉망으로 완성되는 것을 관찰하고, Isaac Z. Schlueter이 만들게 됬다고 한다. (답답해서 직접 뛴 케이스다)

npm에 대한 사용법에 대한 설명은 링크된 사이트를 참고하면 좋을 것 같다 - 모듈화와 npm, poiemaweb



package.json

먼저 npm Docs에서는 package.json에 대해 뭐라고 써놨는지 보자. (만든 분들이 쓴거니까..)

You can add a package.json file to your package to make it easy for others to manage and install. Packages published to the registry must contain a package.json file.

  • lists the packages your project depends on
  • specifies versions of a package that your project can use using semantic versioning rules
  • makes your build reproducible, and therefore easier to share with other developers

기본적으로는 package.json은 문서다.

개발자가 배포한 패키지에 대해, 다른 사람들이 관리하고 설치하기 쉽게 하기 위한 문서.

npm에 패키지를 배포하고 npm registry에 올리기 위해서 반드시 필요한 문서파일이다.

  • 자신의 프로젝트가 의존하는 패키지의 리스트
  • 자신의 프로젝트의 버전을 명시
  • 다른 환경에서도 빌드를 재생 가능하게 만들어, 다른 개발자가 쉽게 사용할 수 있도록 한다.

즉, npm이라는 오픈소스 패키지 생태계를 사용하기 위한 명세이자, 프로젝트의 의존성 관리를 위한 명세, 또 이 생태계로의 배포를 위한 명세라고 볼 수 있다.

프로젝트의 개발만을 위한 목적인지, 패키지를 배포하기 위한 목적인지에 따라 용도가 갈릴 수 있겠다라고 생각했다.
일반적으로 패키지를 불러와서 프로젝트를 개발하는게 목적이라면, 의존성 관리에 대한 명세가 더 중요할 것이다.



구성요소

package.json은 확장자로 알 수 있듯, json파일로 속성-값의 쌍으로 이루어져 있는데,

npm에서 이 속성을 field라고 표현하고 있다.

그렇다면 package.json 파일 내에 어떤 field들로 구성되는지 확인해보자.


기본 구성 요소

1
$ npm init -y

처음 기본 설정 값으로 package.json을 생성하면

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "PROJECT_DIRECTORY",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

위와 같이 생성된다. npm을 사용하는데 기본적으로 필요한 field니까 생성해 줬다고 생각한다.

각 field에 대해서 왜 필요할지에 대해 생각하면서, 읽어보자.



“name”, “version”

npm에 따르면, “name”과 “version”은 반드시 있어야 하는 fields이다.

이 fields가 누락되면 패키지는 설치될 수 없다.

"name" : 말그대로 이 패키지의 이름을 나타낸다. 이름에는 규칙이 있다.

기본 규칙

  • must be lowercase, 소문자로 작성되어야 한다.
  • must be one word, 한 단어로 작성되어야 한다.
  • may contain hyphens and underscore, -(하이픈)이나 _(언더스코어)를 포함할 수 있다.

+상세 규칙

"version": semantic versioning guidelines를 따르며, x.x.x의 형태로 작성해야한다.

간단히 말하면, [Major].[Minor].[Patch]의 형태를 따른다.

semantic versioning(유의적 버전)에 대한 내용은 이 글에 잘 설명되어 있다.
버전 네이밍에 대한 규칙은 회사나 단체에 따라 다르지만, 대부분 이와 비슷한 형태를 띄니 한 번 봐두는 것도 좋을 것 같다.

Example

1
2
3
4
{
"name": "my-awesome-package",
"version": "1.0.0"
}

“description”

문자열로 기술한 패키지에 대한 설명. npm에서 검색되었을 때 리스트에 표시되어 사람들이 패키지를 찾아내고 이해할 수 있는데 도움을 준다.


“main”

패키지의 진입점(entry point)이 되는 모듈의 ID이다.

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

패키지 root의 상대경로로 지정해야 한다. 지정하지 않은 경우, root 폴더의 index.js로 기본값이 설정된다.


“scripts”

패키지의 생명주기에서 다양한 타이밍에 자주 사용할 command를 alias(별칭)을 통해 지정해 둘 수 있는 dictionary

Shell Command(CLI)에 대한 상식이 뒷받침된다면, 유용한 command를 지정해두고 사용하는데 편리할 것이다.

Example

흔한 예제를 찾다가 가장 많이들 알 것 같은 create-react-apppackage.json을 일부 가져왔다.

facebook/create-react-app/package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"scripts": {
"build": "cd packages/react-scripts && node bin/react-scripts.js build",
"changelog": "lerna-changelog",
"create-react-app": "node tasks/cra.js",
"e2e": "tasks/e2e-simple.sh",
"e2e:docker": "tasks/local-test.sh",
"postinstall": "npm run build:prod -w react-error-overlay",
"publish": "tasks/publish.sh",
"start": "cd packages/react-scripts && node bin/react-scripts.js start"
// ...
}
}

이처럼 value로 일련의 command(명령어)를 정의해 두고 key로 지정한 alias를 이용해 간편하게 호출 할 수 있다.

ex) npm start


“keywords”

키워드를 문자열 배열로 설명. description과 마찬가지로 npm에서 검색되었을 때 리스트에 표시되어 사람들이 패키지를 찾아내고 이해할 수 있는데 도움을 준다.


“author”

배포자 한 사람을 위한 field로, 다수의 사람을 표시하기 위해서는 “contributors” field로 작성해야 한다.


“license”

배포한 패키지에 대해 패키지 사용자가 패키지를 사용하는데 어떤 권한과 제한 사항이 있는지 알기 위해 license를 명시해야 한다.

이외에도 더 많은 설정을 위한 field가 있지만, 기본적인 부분만 짚을 예정으로 추가적인 부분은 npm Docs - package.json을 참고하길 바란다.



쓰고보니 프젝만 만들면 되는데.. 필요한가..?

위 항목들이 대부분 패키지 배포를 위한 소개나 명세들이다.

프로젝트의 개발만이 목적이라면, 사실 대부분 신경쓰지 않아도 되는 항목들이긴 하다.

위 항목들 다 지우고, 사용할 패키지에 대한 의존성만 남겨도, 잘 돌아가고 문제없다.

하지만, 꼭 배포의 목적이 아니더라도 협업을 하는 사람들 사이에 프로젝트에 대한 전반적인 소개와 내용을 전달하는데, README이외의 정형화된 수단이라고 생각한다면, 적당히 기재해 줄만 하다고 생각한다.



의존성 관련 항목

프로젝트 개발의 목적이라면, 이게 더 중요하다.


“dependencies” & “devDependencies”

패키지의 이름에 해당 패키지의 버전 범위(SemVer)를 매핑한 형태의 객체로 지정한다.

SemVer(유의적 버전)

SemVer 더 알아보기

해당 패키지, 프로젝트가 어떤 외부 라이브러리에 의존성(dependency)을 가지고 있는지,

프로젝트가 의존하고 있는 패키지를 일괄적으로 관리하기 위한 필드이다.


다시 말해, 해당 프로젝트가 어떤 라이브러리를 가지고 있어야 제대로 구동될 수 있는지 명세되어 있다고 보면 된다.

또, 해당 필드를 이용하면, 협업을 할 때와 같이 여러사람이 동시에 작업을 해야할 때,

팀 내에서 동일한 개발환경을 빠르게 구축할 수 있도록 하는 장점을 가지고 있다.


package.json내 기본적인 작성 방법은 dependenciesdevDependencies 둘 다 똑같다.

1
2
3
4
5
6
7
8
9
10
{
"dependencies": {
"hexo": "^5.0.0",
"hexo-deployer-git": "^3.0.0",
"hexo-generator-archive": "^1.0.0",
"hexo-generator-category": "^1.0.0",
"hexo-generator-feed": "^3.0.0"
// ...
}
}
1
2
3
4
5
6
7
8
9
10
11
{
"devDependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"alex": "^8.2.0",
"eslint": "^7.30.0",
"lerna-changelog": "~0.8.2"
// ...
}
}

사용법

사용하고자 하는 패키지를 아래와 같이 다운받으면, dependencies 필드에 자동으로 install한 ‘패키지이름’과 ‘버전’이 기록된다.

1
$ npm install <package>

devDependencies 필드에 기록하려면, 아래와 같이 --save-dev(또는 축약-D)옵션을 넣어주면 된다.

1
$ npm install --save-dev <package>

devDependencies는 개발시에만 필요한 의존 패키지들을 의미한다.

예를 들어, 테스트를 위한 패키지나 트랜스파일러와 같이 배포시에는 필요없는 패키지들을 이 devDependencies에 포함 시킨다.

npm Docs에서도 아래와 같이 굵은 글씨로 강조하고 있다.

Please do not put test harnesses or transpilers or other “development” time tools in your dependencies object.



결론

나는 npm을 보통 프로젝트에서 사용할, 유용한 패키지를 불러오기 위한 용도로 많이 사용했다.

npm은 npm이라는 package 생태계에 활성화를 위하고, 그렇기 때문에 배포 위주로 Docs를 작성해 놓은 것 같다. (하지만 난 아직 쭈구리 개발자인걸…)

인생사 새옹지마..

언젠가 기깔난(?) 패키지를 만들게 될 수도 있는 거다.

위 소개한 ‘필드’외에도 굉장히 많은 종류의 필드가 npm 공식 홈페이지에 소개 되어 있다.

앞서 말했지만, 패키지를 배포해 오픈소스 생태계에 기여하고 싶은 사람은 공식 홈페이지를 참조해 더 알아보면 좋을 것 같다.

오픈소스 생태계에 배포하고 기여할 수 있는 개발자가 되도록 노력하자.


참고