본문 바로가기
공뷰/js,ts

package.json과 package-lock.json의 차이(+ npm install과 npm ci의 차이)

by WOOSERK 2023. 3. 24.
당신은 이제까지 작성한 package.json의 개수를 일일이 기억하는가?

 

저는 늘 npm에게 맡겼기 때문에 기억하지 못합니다. 알아서 잘하겠거니 하고 큰 관심을 갖지 않았습니다.

 

하지만 노드 개발자가 package.json조차 제대로 알지 못하는 것은 어불성설. 이 기회에 package-lock.json과 함께 알아보려고 합니다.

 

package.json

어떤 기술을 공부하는 데에는 공식 문서만한 것이 없습니다.

 

package.json을 알아보기 위해 npm docs에 들어가면 다음과 같은 화면이 반겨줍니다.

 

 

우리가 필요한 것은 dependencies 항목이고, 그중 중요한 것 몇 가지만 살펴보겠습니다.

 

dependencies

Dependencies are specified in a simple object that maps a package name to a version range.
The version range is a string which has one or more space-separated descriptors.

종속성은 패키지 이름과 버전의 범위가 매핑된 개체이며, 버전 범위는 공백으로 구분된 설명자가 하나 이상 있는 문자열입니다.

 

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

테스트 도구나 트랜스파일러 등의 개발 단계에 쓰이는 도구는 여기에 넣지 말라고 합니다. 이런 경우 npm install을 입력할 때 --save-dev 옵션을 붙여 devDependencies(개발 종속성)로 설치해야 합니다.

 

 

그리고 다양한 버전 범위 표현이 있는데 궁금하신 분은 아래 링크로.

https://github.com/npm/node-semver#versions

 

GitHub - npm/node-semver: The semver parser for node (the one npm uses)

The semver parser for node (the one npm uses). Contribute to npm/node-semver development by creating an account on GitHub.

github.com

 

제가 했던 프로젝트 package.json의 일부를 가져왔습니다.

 

^밖에 없습니다. ^가 무슨 의미일까요? 그 전에 소프트웨어 관리에 사용되는 버전 표현 방식을 알고 갑시다.

 

Semantic Versioning

1.0.0과 같은 버전 표현 방식을 Semantic Versioning이라고 합니다(줄여서 SemVer). 각 숫자의 의미는 [major, minor, patch]를 의미합니다. 

메이저: API가 변경되어 의존성을 이용하던 기존 코드를 깨뜨릴 수 있음
마이너: 순수하게 기능 추가만 있음(기존 코드를 깨뜨리지 않음)
패치: API에 영향을 주지 않는 내부 구현 개선과 버그 수정
From. 구글 엔지니어는 이렇게 일한다

 

^

^은 캐럿 범위 표현식입니다. 가장 왼쪽에 있는 0이 아닌 요소를 수정하지 않는 변경을 허용합니다. 예시를 가져왔습니다.

  • ^1.2.3 := >=1.2.3 <2.0.0-0
  • ^0.2.3 := >=0.2.3 <0.3.0-0
  • ^0.0.3 := >=0.0.3 <0.0.4-0

예를 들어 ^1.2.3이면 맨 왼쪽의 1을 제외한 2와 3의 변경, 즉 마이너와 패치 버전이 달라도 됩니다.

^0.2.3이면 패치 버전이 달라도 범위에 포함됩니다. 마이너 버전이 다르면 포함되지 않습니다.

그럼 ^0.0.3은? 0.0.3988794와 같은 버전도 포함되는 것이겠죠?

 

 

npm install 명령어를 입력하면 node_modules폴더에 패키지를 설치할 때 package.json에 표현된 범위 내에서 사용 가능한 최신 버전을 설치합니다. 그래서 간혹 업데이트된 버전으로 패키지를 설치해 오류가 발생할 수 있습니다.

 

모든 패키지를 정확한 버전으로 설치하면 오류를 피할 수 있습니다.물론 package.json에도 범위가 아닌 버전을 명시할 수 있지만 그런 경우는 드뭅니다.

 

그래서 npm v5부터 package-lock.json을 지원하게 됩니다.


package-lock.json

package-lock.json is automatically generated for any operations where npm modifies either the
node_modules tree, or package.json.

package-lock.json은 node_modules 트리package.json이 수정되는 작업에 자동으로 생성됩니다.

 

package-lock.json의 목적은 정확히 동일한 종속성을 설치하는 것입니다.

 

앞선 package.json을 가져왔던 프로젝트의 package-lock.json입니다. 정확한 버전이 명시된 것을 확인할 수 있습니다.


요약해 빨리

요약하면 package.json은 범위로 패키지의 버전을 표현하고, package-lock.json은 정확한 패키지의 버전을 명시합니다.

 

그래서 package-lock.json은 node_modules 없이 배포한다면 반드시 필요합니다. 그래야 협업할 때 버전이 달라서 오류가 나는 상황을 방지할 수 있습니다.

 

+) npm installnpm ci의 차이

npm install

npm install은 package.json을 참고하여 node_modules를 만듭니다. 

 

그래서 npm install은 먼저 package-lock.json이 있는지 확인하고, 있다면 명시된 버전이 범위 안에 포함되는지 확인합니다. 포함되면 설치하고, 아니라면 최신 버전을 설치한 뒤 package-lock.json을 업데이트합니다.

 

업데이트를 원하지 않으면 npm ci를 사용하면 됩니다.

 

npm ci

npm ci는 package-lock.json를 참고하여 node_modules를 만들고, 만약 package.json의 종속성 트리와 다르면 오류가 발생합니다.

 

즉, 패키지의 버전이 하나라도 다르면 실행되지 않습니다. 그렇기 때문에 package.jsonpackage-lock.json이 모두 필요합니다.

 

또 npm ci는 보통 npm install보다 빠릅니다. 버전 업데이트를 확인할 필요 없이 명시된 버전만 설치하기 때문입니다.

 

하지만 node_modules가 존재한다면, 이를 삭제하고 다시 설치하기 때문에 항상 빠르다고 장담할 수는 없습니다. 그래서 주로 CI/CD나 테스트에 사용됩니다.

 

 

예시와 함께 이해해봅시다.

당신은 다음과 같은 package.json을 가지고 있습니다.

"foo": "^2.3.0"

 

npm install을 실행하면 package-lock.json은 아래처럼 생성될 것입니다.

"foo": "2.3.0"

 

며칠 뒤, foo의 마이너 버전 업데이트(2.4.0)가 발생하면 다음과 같은 일이 발생합니다.

 

npm install - package-lock.json의 버전이 범위 안에 있으므로 2.3.0을 설치합니다.

npm ci - package-lock.json만 보고 2.3.0을 설치합니다.

 

 

이제 package.json을 수동으로 업데이트합니다.

"foo": "^2.4.0"

 

명령어를 다시 실행합니다.

npm install - package-lock.json의 버전이 범위 안에 없으므로 2.4.0을 설치하고, package-lock.json을 "foo": "2.4.0"으로 변경합니다.

 

npm ci - package-lock.json만 보고 오류가 발생합니다.

 

 

위 예시는 아래에서 가져왔습니다.

https://medium.com/helpshift-engineering/package-lock-json-the-complete-guide-2ae40175ebdd

 

package-lock.json: The Complete Guide

What is package-lock.json? And why should you care?

medium.com