node 기반 프로젝트에서는 package.json에서 npm에서 받은 라이브러리들을 관리하게 된다.
그런데 npm i {package_name}
명령어로 라이브러리 설치 시 package-lock.json 파일이 추가로 생성되는 것을 볼 수 있다. package.json과 유사하지만 조금은 다른 구성의 이 파일은 왜 생성되는걸까??
결론부터 말하자면 각 패키지(라이브러리)들의 정확한 버전을 기록하기 위해 사용하는 것이다. 즉, 일종의 세이브 파일이라고 볼 수 있다.
package.json에는 시멘틱 버저닝으로 인하여 느슨한 버전 명시가 되어있기에 별도의 package-lock.json을 통해 명확한 버전 명시를 하는 것이다.
협업 시 정확한 버전을 공유하는 것을 당연한 일이다. 하지만 사실 package.json 파일에는 버전이 명확하게 지정된 것은 아니다.
예를 들어 React를 설치했다고 가정했을 때 아래와 같이 dependencies에 버전이 기록 된다.
// package.json 파일
{
"name": "lock_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^16.8.2"
}
}
16.8.2 버전의 React를 설치했다는 의미인데 여기에 ^
표시가 붙어있다. 이 기호는 시멘틱 버저닝을 의미하는 것으로 일종의 버전 관리 규칙이다. 시멘틱 버전의 구조는 아래와 같다.
버전은 기본적으로 MAJOR.MINOR.PATCH
구조를 가지고 있다.
react 16.8.2
- 16: MAJOR (주 버전, 호환되지 않는 변경)
- 8: MINOR (기능 추가, 하위 호환 유지)
- 2: PATCH (버그 수정, 하위 호환 유지)
시멘틱 기호의 의미
기호 | 의미 |
---|---|
없음 | 명시된 버전이 정확히 설치됨 ex) 16.8.2 |
^ (캐럿) | 같은 MAJOR 안에서 가능한 최신 MINOR + PATCH ex) 16.X.X |
~ (틸드) | 같은 MINOR 안에서 가능한 가장 최신 PATCH ex) 16.8.X |
>=, <=, <, > (범위 기호) | 특정 범위 직접 지정 |
따라서 내 package.json에서는 16.X.X 버전 중 가장 최신 react를 사용한다고 명시되어 있는 것이다.
이렇게 느슨한 버전 명시를 하는 이유는 해당 라이브러리의 소소한 업데이트(버그픽스 등)를 대비하기 위한 것이다.
명확하게 버전 명시한 경우
16.8.2 버전에 치명적인 오류가 생겨 16.8.3 버전으로 수정된 상황에 npm i
로 패키지를 설치한다면 여전히 버그가 있는 16.8.2버전이 설치된다.
느슨하게 버전 명시한 경우
package.json에 ^16.8.2라고 적혀있지만 실제로는 16.X.X 버전 중 가장 최신인 16.8.3을 설치하게 된다.
하지만 반대로 package.json의 느슨한 버저닝 때문에 협업 시 문제가 발생할 수 있다.
A직원은 16.8.2 버전으로 업무를 하다가 B직원이 새로 들어와 저장소를 클론하고 패키지를 설치한다. 하지만 그 사이에 16.9.3 버전으로 업데이트 되었고 B직원은 이 버전을 설치하게된다.
이런 문제를 해결하기 위해 package-lock.json 파일을 통해 명확한 버전을 명시하는 것이다.
// package-lock.json 파일
{
"name": "lock_test",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lock_test",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"react": "^16.8.2"
}
},
"node_modules/react": {
"version": "16.8.2", // 명확하게 버전 명시
"resolved": "https://registry.npmjs.org/react/-/react-16.8.2.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAy96Br6YbpEU1LSzV5dYtjMkMDg==",
"engines": {
"node": ">=0.10.0"
}
}
}
}
package-lock.json 파일의 node_modules/react 부분을 보면 시멘틱 버저닝 없이 명확하게 버전을 기록한 것을 볼 수 있다. 이렇게 package-lock.json 파일이 존재하는 경우 npm i
명령어 실행 시 lock파일에 명시된 버전으로 패키지를 설치한다.
특정 버전을 사용하다가 업데이트해야하는 경우 2가지 방법으로 해결할 수 있다.
현재 설치된 버전이 최신이 아닌 경우 package.json의 시멘틱 버저닝 기준으로 최신 버전 업데이트. 이 경우 package-lock.json도 함께 업데이트 됨.
package-lock.json파일을 지우고 npm i
를 수행하면 최신버전을 설치하게 되고 이에 맞는 package-lock.json파일이 새로 생성된다.
이렇게 버전을 최신화한 경우 당연히 package-lock.json의 수정사항도 git에 올려두어야 동료들도 버전을 맞출 수 있을 것이다. 하지만 버전을 업데이트 할 때는 꼭!! 팀원과 이야기해보고 사이드 이펙트를 고려해서 업데이트하는 것이 좋다고 생각한다.