JavaScript 프로젝트를 진행할 때는 주로 npm
과 yarn
같은 패키지 관리 도구를 사용하게 된다. 이러한 패키지 매니저는 패키지의 다운로드, 업데이트, 의존성 관리를 포함한 복잡한 작업을 간편하고 안전하게 처리하는 데 도움을 준다.
이번 글에서는 패키지 매니저의 발전 과정을 살펴보면서 npm
, yarn
, 그리고 yarn berry
의 각각 장단점을 비교해 보겠다.
npm(node package manager)은 JavaScript 런타임 환경인 Node.js의 기본 패키지 관리자이다.
대부분 개발자들은 yarn
패키지 매니저를 많이 사용하는데 어떠한 이유때문에 npm 대신 yarn을 많이 사용하는지 알아보자.
JavaScript 프로젝트에서 노드 모듈은 기본적으로 시멘틱 버저닝(Semantic Versioning)
방식을 사용하여 버전을 관리합니다. 시멘틱 버저닝은 버전을 세 가지 숫자로 나누어 각 숫자가 이전 버전과의 관계를 나타내는 방식입니다. 예를 들어, 버전 번호가 1.2.3일 때, 이 숫자들은 메이저, 마이너, 패치 버전을 의미합니다.
또한, 패키지 버전을 관리할 때 캐럿 기호(^)
를 사용하여 메이저 버전은 고정하고, 마이너 및 패치 버전까지는 업데이트를 허용할 수 있습니다. 예를 들어, 버전이 ^1.2.3이라면, 메이저 버전 1이 유지되는 범위 내에서 1.2.0부터 1.2.4까지의 버전 변경이 가능하다는 의미입니다.
이러한 방식으로 버전을 관리할 때, npm install 명령어를 사용하여 모듈을 설치하면 항상 메이저 버전이 동일한 최신 버전이 설치됩니다. 이로 인해 최신 버전이 출시될 때마다 설치되는 버전이 달라질 수 있는 문제
가 발생할 수 있습니다.
다시 정리하면 버전 변경이 허용되기 때문에 모듈간의 버전이 일치하지 않는 문제
가 발생할 수 있습니다
개발자의 환경에 따라 모듈이 설치되는 순서가 달라질 수 있습니다.
이미 설정된 프로젝트에 새로운 모듈을 추가로 설치할 때, npm install 명령어를 실행하는 개발자와 초기 설치를 진행한 개발자의 설치 순서가 다를 수 있습니다.
npm은 모듈을 추가하는 순서를 기록하지 않기 때문에, 모듈 이름을 알파벳 순으로 정렬하여 순차적으로 설치합니다.
npm은 모듈을 하나씩 순차적으로 설치합니다. 따라서 설치할 모듈이 많을수록 전체 설치 시간이 길어질 수 있습니다.
이로 인해 많은 수의 모듈을 설치할 때 전체 작업이 오래 걸리는 경향이 있습니다.
yarn은 npm의 문제들을 해결함과 동시에 여러 기능을 탑재하여 등장 하였다.
yarn은 모듈의 버전을 고정하기 위해 yarn.lock 파일을 사용합니다. 이 파일은 프로젝트에 사용되는 모든 모듈의 정확한 버전을 기록
하여, 모든 개발자가 일관된 버전의 모듈을 사용할 수 있도록 보장
합니다.
반면, npm은 npm shrinkwrap 명령어를 통해 버전을 .json 파일에 명시하여 이 문제를 해결합니다. 그러나 npm에서는 버전 고정을 할 때마다 명령어를 입력해야 하는 번거로움이 있으며, yarn은 의존성이 변경될 때마다 yarn.lock 파일을 자동으로 업데이트하여 더 간편하게 관리할 수 있습니다.
yarn은 패키지가 제대로 설치되었는지 확인하기 위해 체크섬(checksum)
을 사용합니다. yarn.lock 파일의 resolved 주소 뒤에 위치한 해시값이 체크섬을 나타내며, 이는 패키지 파일의 무결성을 검증하는 중요한 보안 장치 역할을 합니다.
yarn은 다운로드한 패키지를 캐시
하여, 이후 설치 시 훨씬 빠른 속도로 진행됩니다. 또한, yarn은 병렬 다운로드를 지원하여, 모듈을 동시에 설치할 수 있습니다. 반면, npm은 모듈을 순차적으로 설치
하므로, 설치할 패키지가 많을수록 속도 차이가 더 크게 나타납니다.
시간이 지나면서 npm도 많은 개선을 이루었습니다. 이제 package-lock 파일을 통해 버전 고정을 지원하며, 속도 측면에서도 yarn과 크게 차이가 나지 않을 정도로 발전했습니다.
그럼에도 불구하고, 두 패키지 매니저 모두 여전히 해결해야 할 문제들이 존재합니다
npm에서 생성된 node_modules 폴더는 상당히 큰 용량을 차지
합니다. 이를 줄이기 위해 npm
은 호이스팅(hoisting) 기법을 도입
했습니다. 호이스팅은 중복을 줄이는 가장 간단한 방법으로, 각 패키지가 의존하는 다른 패키지들을 최상위로 끌어올려 중복된 패키지가 하나만 남도록 합니다. 이로 인해 불필요한 중복이 제거되지만, 여전히 node_modules 폴더의 용량 문제는 남아 있습니다.
이러한 호이스팅 방식은 때때로 '유령 의존성'
문제를 야기합니다. 즉, 실제로는 직접 설치하지 않았지만, 간접적으로 의존성 때문에 불필요한 패키지가 설치될 수 있습니다. 이로 인해 비효율적인 설치가 발생하고, 필요 없는 패키지들도 함께 설치되게 됩니다.
이러한 문제들, 특히 비효율적인 설치와 유령 의존성 문제는 npm과 yarn이 여전히 해결해야 할 과제로 남아 있습니다. 이에 대응하기 위해, yarn은 2020년 1월에 yarn v2
를 공개하여 이러한 문제들을 해결하고자 했습니다.
Yarn Berry
는 Yarn v2
이상의 버전을 지칭하는 이름입니다. 이에 따라 기존의 Yarn v1은 이제 Yarn Classic이라고 불립니다. Yarn Berry는 Yarn Classic에서 겪었던 문제들을 해결하기 위해 새로운 접근 방식을 도입하였습니다.
최신 버전의 Yarn을 npm을 통해 설치한 후, 버전을 berry로 설정하면 Yarn Berry를 사용할 수 있습니다.
$ npm install -g yarn
$ yarn set version berry
Yarn Berry는 기존의 거대한 node_modules 폴더를 생성하지 않고, 패키지 정보를 .zip 파일로 관리
합니다. 패키지 의존성 정보는 .yarn/cache
폴더에 저장된 압축 파일로 관리되며, .pnp.cjs
파일에 의존성 정보를 기록합니다.
예를 들어, React 패키지의 경우 .pnp.cjs 파일에서 패키지의 위치와 의존성 정보를 확인할 수 있습니다. 이 방식은 디스크 I/O를 줄여 패키지의 위치를 빠르게 찾을 수 있게 하며, 중복 설치를 방지하여 시간과 자원을 절약합니다.
Yarn Berry는 PnP 방식으로 의존성을 압축 파일로 관리하기 때문에(Zero Install), 의존성의 용량이 현저히 줄어듭니다. 예를 들어, 일반적인 node_modules 폴더는 1.2GB 크기에 135,000개의 파일로 구성되지만, Yarn PnP는 139MB 크기의 2,000개 압축 파일로 구성됩니다. 이처럼 의존성의 용량과 파일 수가 줄어들어 Git으로 관리할 수 있게 됩니다.
Zero Install
을 사용하면 다음과 같은 장점이 있습니다