LHJ

I'm a FE developer.

유의적 버전과 버전의 범위

21 Sep 2020 » node_webpack2

유의적 버전과 버전의 범위

유의적 버전

{
  "dependencies": {
    "react": "^16.12.0"
  }
}

앞에 ^ 이 표시가 의미하는 것은 무엇일까?

위 질문에 답하기 전에 버전 관리에 대해서 생각해보자.
만약 프로젝트에서 사용하는 패키지의 버전을 업격하게 제한한다면 어떨까?
프로젝트를 버전업 하는데 꽤 힘들 수 있다.
사용하는 패키지를 전부 버전업해야 하기 때문이다.
어쩌면 우리 프로젝트는 현재 버전에 갖혀 버릴지도 모른다.

그럼 프로젝트에서 사용하는 패키지 버전을 느슨하게 풀어 놓으면 문제가 해결될까?
오히려 여러 버전별로 코드를 관리해야하는 혼란스러움을 겪게될 수 있다.

버전 번호를 관리하기 위한 규칙이 필요한데 이 체계를 유의적 버전이라고 한다.
NPM은 이 유의적 버전(Sementic Version)을 따르는 전제 아래 패키지 버전을 관리한다.

유의적 버전은 주(Major), 부(Minor), 수(Patch) 세 가지 숫자를 조합해서 버전을 관리한다.
위에 설치한 react의 버전은 16.12.0인데 주 버전이 16, 부 버전이 12, 수 버전이 0인 셈이다.

각 버전을 변경하는 기준은 다음과 같다.

  • 주 버전(Major Version) : 기존 버전과 호환되지 않게 변경한 경우
  • 부 버전(Minor Version) : 기존 버전과 호환되면서 기능이 추가된 경우
  • 수 버전(Patch Version) : 기존 버전과 호환되면서 버그를 수정한 경우

버전의 범위

NPM이 버전을 관리하는 방식은 유의적 버전 명세 뿐만아니라 버전의 범위를 자신만의 규칙으로 관리한다.
가장 단순한 것이 특정 버전을 사용하는 경우다.

1.2.3

특정 버전보다 높거나 낮을 경우는 다음과 같이 명시한다.

>1.2.3
>=1.2.3
<1.2.3
<=1.2.3

마지막으로 틸드(~)와 캐럿(^)을 이용해 범위를 명시한다.

~1.2.3
^1.2.3

틸드(~)는 마이너 버전이 명시되어 있으면 패치버전을 변경한다.
예를 들어 ~1.2.3 표기는 1.2.3 부터 1.3.0 미만 까지를 포함한다.
마이너 버전이 없으면 마이너 버전을 갱신한다.
~0 표기는 0.0.0부터 1.0.0 미만 까지를 포함한다.

캐럿(^)은 정식버전에서 마이너와 패치 버전을 변경한다.
예를 들어 ^1.2.3 표기는 1.2.3 부터 2.0.0 미만 까지를 포함한다.
정식버전 미만인 0.x 버전은 패치만 갱신한다.
^0 표기는 0.0.0부터 0.1.0 미만 까지를 포함한다.

과거에 NPM은 틸트를 기본으로 사용했는데 지금은 캐럿을 사용한다.
그 이유는 아래와 같다.

보통 라이브러리 정식 릴리즈 전에는 패키지 버전이 수시로 변한다.
0.1에서 0.2로 부버전이 변하더라도 하위 호환성을 지키지 않고 배포하는 경우가 빈번하다.
~0로 버전 범위를 표기한다면 0.0.0부터 1.0.0 미만까지 사용하기 때문에 하위 호환성을 지키지 못하는 0.2로도 업데이트 되어버리는 문제가 생길 수 있다.

반면 캐럿을 사용해 ^0.0으로 표기한다면 0.0.0부터 0.1.0 미만 내에서만 버전을 사용하도록 제한한다.
따라서 하위 호환성을 유지할 수 있다.

npm view react versions

이렇게 틸트를 사용하게되면 0.14.9 버전을 설치하게 되면서(부버전을 업데이트) 이전버전과의 호환성이 깨지게 된다. (정식 릴리즈 전에는 호환성을 잘 안지키므로)
이를 방지하기 위해서 캐럿(^) 방식을 사용한다.

마이너 버전(부 버전)은 변경 안하고 패치(수 버전) 버전만 변경하면서 설치한 것을 확인할 수 있다.