package-lock.json은 왜 필요할까?
어느날 부터인가 npm을 사용하면 package-lock.json
파일이 같이 생기기 시작했습니다.
이 파일의 정체가 궁금했지만 바쁘다는 핑계로 넘어가기를 몇 차례… 이제서야 package-lock.json
파일이 왜 생겼는지 찾아 보았씁니다.
package-lock.json 파일이란
package-lock.json
파일은 npm을 사용하에서 node_modules
트리나 package.json
파일을 수정하게 되면 자동으로 생성되는 파일입니다.
이 파일은 파일이 생성되는 시점의 의존성 트리에 대한 정확한 정보를 가지고 있습니다.
아래는 package-lock.json
파일의 일부입니다.
{
"name": "db-http-proxy",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
...
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"abstract-logging": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-1.0.0.tgz",
"integrity": "sha1-i33q/TEFWbwo93ck3RuzAXcnjBs="
},
"accept": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/accept/-/accept-3.0.2.tgz",
"integrity": "sha512-bghLXFkCOsC1Y2TZ51etWfKDs6q249SAoHTZVfzWWdlZxoij+mgkj9AmUJWQpDY48TfnrTDIe43Xem4zdMe7mQ==",
"requires": {
"boom": "7.2.0",
"hoek": "5.0.3"
}
},
}
}
package-lock.json이 필요한 이유
package.json
파일의 의존성 선언에는 version range
가 사용됩니다.
version range
란 특정 버전이 아니라 버전의 범위를 의미합니다.
가장 흔한 예로 npm install express
를 실행하게 되면 package.json
파일에는 “^4.16.3”(Caret Ranges)로 버전 범위가 추가됩니다.
Caret Ranges
^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-beta.2
:=>=1.2.3-beta.2 <2.0.0-0
1.2.3 버전의 시험판은 베타 2 이상인 경우 허용됩니다.
따라서 1.2.3-beta.4는 허용되지만 1.2.4-beta.2는 다른 [주, 부 패치] 튜플의 시험판이기 때문에 허용되지 않습니다.^0.0.3-beta
:=>=0.0.3-beta <0.0.4-0
0.0.3 버전의 시험판은 베타보다 크거나 같은 경우에만 허용됩니다.
따라서 0.0.3-pr.2가 허용됩니다.
“^4.16.3”(Caret Ranges)로 버전 범위가 추가된 package.json
파일로 npm install
을 실행하면 현재는 4.16.3 버전이 설치되지만 express
의 새로운 minor, patch가 publish 되면 동일한 package.json
파일로 npm install
을 실행해도 4.17.3이나 4.16.4 같은 업데이트된 버전이 설치됩니다.
물론 대부분의 경우에는 문제가 없지만 간혹 업데이트된 버전이 오류를 발생시키는 경우가 있습니다.
package-lock.json
파일은 의존성 트리에 대한 정보를 가지고 있으며 package-lock.json
파일이 작성된 시점의 의존성 트리가 다시 생성될 수 있도록 보장합니다.
아래 시나리오를 통해서 설명하겠습니다.
시나리오 1 : package-lock.json 파일을 소스 저장소에 커밋하지 않은 경우
- 박과장이 npm으로 프로젝트를 만들어서 git에 소스코드를 push합니다.
이때 node_modules 폴더를 제외하고 package.json 파일만 커밋합니다. - 김대리는 소스코드를 pull하고
npm install
을 실행합니다. - 의존성 트리의 일부 버전이 박대리와 다르게 설치됩니다.
- 프로그램 실행시 오류가 발생합니다.
- 김대리는 오늘도 야근을 합니다.
시나리오 2 : package-lock.json 파일을 소스 저장소에 커밋한 경우
- 박과장이 npm으로 프로젝트를 만들어서 git에 소스코드를 push합니다.
이때 node_modules 폴더를 제외하고 package.json 파일과 package-lock.json 파일을 같이 커밋합니다. - 김대리는 소스코드를 pull하고
npm install
을 실행합니다. - 의존성 트리가 박대리가 세팅한 환경과 동일하게 설치됩니다.
- 프로그램이 정상적으로 실행됩니다.
- 김대리는 정시 퇴근을 합니다.
실제로 앱에서 사용하고 있는
react-native-router-flux
를 예로 들어볼까요?
아래는 프로젝트에서npm ls
로 조회한 의존성 트리에서react-native-router-flux
부분만 발췌한 부분입니다.
├─┬ react-native-router-flux@4.0.0-beta.24
│ ├── lodash.isequal@4.5.0
│ ├── mobx@3.6.2
│ ├─┬ mobx-react@4.4.3
│ │ └── hoist-non-react-statics@2.5.0
│ ├── opencollective@1.0.3
│ ├── path-to-regexp@2.2.0
│ ├── prop-types@15.6.1]
│ └── react-navigation@1.0.0-beta.19
pakcage.json
파일에 버전을 "react-native-router-flux": "4.0.0-beta.24"
지정해도 react-native-router-flux
프로젝트 내부의 package.json
파일에 react-navigation
이 Caret Range로 선언되어 있기 때문에 react-navigation
의 버전은 npm install
을 수행하는 시점에 따라서 달라집니다.
실제로 문제가 있는 react-navigation
1.0.0-beta21 버전이 릴리즈 된 이후 앱 빌드가 실패해서 이슈가 되기도 했습니다.
결국 react-native-router-flux
개발자가 Caret Range를 제거하는 패치를 했습니다.
package-lock.json
파일은 npm에 의해서 프로젝트의 node_modules
나 package.json
이 수정되는 경우 생성되거나 업데이트되며 당시 의존성에 대한 정보를 모두 가지고 있습니다.
따라서 생성된 package-lock.json
파일은 소스 저장소에 커밋해야 합니다.
(반드시 커밋할 필요는 없지만 저장소에 커밋하는 것을 강력추천합니다.)
요약
package-lcok.json
파일은 의존성 트리에 대한 정보를 모두 가지고 있습니다.package-lock.json
파일은 저장소에 꼭 같이 커밋해야 합니다.package-lock.json
파일은node_modules
없이 배포하는 경우 반드시 필요합니다.
TroubleShooting
아래 로그처럼
integrity checksum failed
오류가 나는 경우
npm cache clean --force
실행WARN registry Unexpected warning for https://registry.npmjs.org/: Miscellaneous Warning EINTEGRITY: sha1-w39Yfwo4PHAZ6CESDow/WPDSJ3I= integrity checksum failed when using sha1: wanted sha1-w39Yfwo4PHAZ6CESDow/WPDSJ3I= but got sha512-EhmUQodKB0sdzPPrbIWbGqA5cQeTWxYrAgNeeT1rLZWtD3tbNTnphz8J4vkXI3cPgBNlXBjzEbzDzq0Nwi4f9A==. (2896 bytes)