안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

자바스크립트 (JavaScript)

[JavaScript] package.json, package-lock.json

피그브라더 2020. 8. 27. 11:19

npm으로 Node.js 패키지들을 관리하는 프로젝트의 경우, 프로젝트 루트 폴더에는 Node.js 패키지들이 설치된 node_modules 폴더와 함께 package.json, package-lock.json 파일이 위치하고 있다. 이번 포스팅에서는 Node.js 패키지를 활용하여 프로젝트를 진행하는 개발자들이 node_modules 폴더, package.json 파일, 그리고 package-lock.json 파일에 대해 최소한으로 알고 있어야 하는 것들에 대해 정리해보기로 하였다. 틀린 내용이 있다면 댓글로 지적 바란다.

 

※ Node.js 및 npm에 대한 기본적인 내용은 여기를 참고하기 바란다.

※ 본 포스팅은 npm 6까지 사용하던 lockfileVersion 1을 기준으로 작성되어, 최신 lockfileVersion과는 다르다.

 

1. node_modules 폴더 (의존성 트리)

npm을 이용하여 설치하는 Node.js 패키지들이 위치하는 곳이다. 이 폴더의 구조는 곧 해당 프로젝트에서 사용하는 Node.js 패키지들의 의존성 트리를 나타낸다. node_modules 폴더 안에는 설치된 Node.js 패키지들에 해당하는 폴더들이 존재하고, 각 패키지 폴더 안에도 필요한 경우(뒤에서 설명) 또 다른 Node.js 패키지들에 해당하는 폴더들이 존재할 수 있기 때문이다. 참고로, 일반적인 경우 이 폴더는 버전 관리 시 커밋 대상에서 제외가 된다. 곧 이어서 설명할 package.json 파일과 package-lock.json 파일만 있으면, "npm install" 명령어를 통해 node_modules 폴더의 의존성 트리와 동일한 형태로 Node.js 패키지들을 설치할 수 있기 때문이다.

 

2. package.json 파일과 npm install

프로젝트에서 필요로 하는 Node.js 패키지들에 대한 정보를 JSON 형태로 표현하는 파일이다. 필수적으로 해당 프로젝트에 관한 "name" 및 "version" 속성이 명시되어야 하며, 설치되어야 할 Node.js 패키지들의 목록은 "dependencies" 또는 "devDependencies" 속성에 명시가 된다. package.json 파일은 "npm install" 명령어로 Node.js 패키지를 설치할 때마다 생성되거나 업데이트된다. "dependencies" 속성에는 --save 옵션으로 "npm install {패키지명}" 명령어를 실행할 때 설치되는 Node.js 패키지가 등록되고, "devDependencies" 속성에는 --save-dev 옵션으로 "npm install {패키지명}" 명령어를 실행할 때 설치되는 Node.js 패키지가 등록된다. 이때 "devDependencies" 속성에 명시되는 패키지들은 배포 시에는 사용되지 않고 개발 시에만 사용된다는 특징이 있다. 참고로, "npm install {패키지명}" 명령어를 실행할 시 특별히 옵션을 지정해주지 않으면 기본적으로 --save 옵션이 지정된다. 즉, 설치되는 패키지는 기본적으로 "dependencies" 속성에 등록이 된다.

 

여기서 '배포 시에는 사용되지 않고 개발 시에만 사용'이 의미하는 것은 무엇일까? 간단하다. 테스트, 컴파일, 코드 스타일 검사 등의 목적으로 사용되는 Node.js 패키지들은 배포하려는 실서버 환경에서는 설치될 필요가 없다. 따라서 실서버 환경에서는 "npm install" 명령어 대신 "npm install --production" 명령어를 실행하는데, 이는 package.json 파일에서 오로지 "dependencies" 속성에 등록된 Node.js 패키지들만 설치하게 된다. 즉, 개발 시에만 사용되는 Node.js 패키지들은 설치하지 않는 것이다.

 

일반적으로 node_modules 폴더는 커밋하지 않는 반면, package.json 파일은 반드시 커밋하게 된다. 해당 프로젝트를 pull 하여 받아온 뒤 "npm install" 명령어를 수행하면, node_modules 폴더를 생성하고 package.json 파일을 참조함으로써 필요한 Node.js 패키지들을 일괄 설치할 수 있기 때문이다. 그런데 여기서 문제가 존재한다. package.json 파일에 명시되는 각 Node.js 패키지의 버전 정보는 정확한 값이 아닌 범위 값(EX. ^4.16.3)이라는 것이다. 그 결과, 동일한 package.json 파일로 "npm install" 명령어를 실행하더라도 npm 버전이 다르거나 특정 패키지가 추후 업데이트되거나 하는 등의 이유로 인해 의도와는 약간 다른 의존성 트리를 나타내는 node_modules 폴더를 만들어낼 수 있다. 이처럼 배포 당시 개발자가 의도한 버전이 아닌 다른 버전의 패키지가 설치된다면 프로젝트의 동작에 오류가 발생할 수도 있다. 이러한 문제를 해결하기 위해 등장한 것이 바로 이어서 설명할 package-lock.json 파일이다.

 

3. package-lock.json 파일

package-lock.json 파일은 npm을 통해 node_modules 폴더의 내용이나 package.json 파일의 내용을 생성하거나 업데이트할 때 자동으로 생성되거나 업데이트되는 파일로, Node.js 패키지들의 업데이트 여부와 상관없이 언제나 동일한 의존성 트리의 형태로 패키지들을 설치할 수 있도록 보장해준다. 즉, node_modules 폴더의 의존성 트리 구조를 기록하는 이 파일이 존재하면 "npm install" 명령어 실행 시 배포 당시 개발자가 의도한 버전대로 Node.js 패키지들을 설치할 수 있게 된다. 따라서 이 파일 또한 버전 관리 시 반드시 커밋 대상에 포함시키는 것이 좋다. 그렇지 않으면 package.json 파일의 한계로 인해 버전의 문제가 발생할 수도 있다.

 

package-lock.json 파일의 "dependencies" 속성에는 설치될 각 Node.js 패키지에 대한 정보가 다음과 같은 형태로 표현된다. (EX. "react-router" 패키지)

{
  "name": "project-name",
  "version": "0.1.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    ...,
    "react-router": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
      "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
      "requires": {
        "@babel/runtime": "^7.1.2",
        "history": "^4.9.0",
        "hoist-non-react-statics": "^3.1.0",
        "loose-envify": "^1.3.1",
        "mini-create-react-context": "^0.4.0",
        "path-to-regexp": "^1.7.0",
        "prop-types": "^15.6.2",
        "react-is": "^16.6.0",
        "tiny-invariant": "^1.0.2",
        "tiny-warning": "^1.0.0"
      },
      "dependencies": {
        "isarray": {
          "version": "0.0.1",
          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
        },
        "path-to-regexp": {
          "version": "1.8.0",
          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
          "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
          "requires": {
            "isarray": "0.0.1"
          }
        }
      }
    },
    ...
  }
}
  • "react-router" : Node.js 패키지 이름으로, node_modules 폴더 내에 존재한다.
  • "version" : 설치된 "react-router" 패키지의 정확한 버전을 의미한다.
  • "requires" : "react-router" 패키지가 의존하는 다른 패키지들의 목록으로, "react-router" 패키지 폴더에 존재하는 package.json 파일의 "dependencies" 속성에 명시된 패키지들의 목록과 같다. 여기에 명시된 패키지는 반드시 설치되어 기본적으로는 node_modules 폴더에 존재해야 한다. 만약 두 개의 패키지가 같은 패키지에 의존하는데 다른 버전을 요구한다면 하나의 버전은 node_modules 폴더가 아닌 해당 패키지 폴더 내에 존재한다.
  • "dependencies" : "react-router" 패키지가 의존하는 패키지들 중, 기본적으로 node_modules 폴더에 설치된 버전과 다른 버전을 요구하는 패키지들의 목록이 이곳에 명시된다. 즉 여기에 명시되는 패키지는 다른 패키지에서도 의존하고 있는 패키지라는 것을 추론할 수 있고, 그 패키지가 의존하고 있는 버전이랑 "react-router" 패키지가 의존하고 있는 버전(1.8.0)이 다르기 때문에 여기에 명시되어 있는 것이다. 그리고 앞서 말했듯 package-lock.json 파일의 내용은 node_modules 폴더의 의존성 트리 구조를 나타내기 때문에, 이곳에 명시되는 패키지들은 실제로 "react-router" 패키지 폴더 내부에 존재하고 있다.

 

결국, 여기에 명시되는 "dependencies" 속성들의 계층이 곧 node_modules 폴더의 계층과 완전히 동일하다. 그리고 "dependencies" 속성에 나열되어 있는 각 패키지는 정확한 버전이 명시되어 있다. 따라서 원래의 node_modules 폴더와 똑같은 node_modules 폴더를 복원할 수 있게 된다.

 

 

 

 

 

 

본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.

https://hyunjun19.github.io/2018/03/23/package-lock-why-need/

https://pewww.tistory.com/11
https://stackoverflow.com/questions/52926922/package-lock-json-requires-vs-dependencies

https://pewww.tistory.com/11
https://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies