npm
과 yarn
은 node
로 프로젝트를 진행할 때 대중적으로 많이 사용되는 패키지 관리 툴로 그 중 yarn
은 기존의 npm
이 가지고 있던 문제점들을 해결하기 위해 등장했습니다.
두 패키지 매니저 모두 현재 수 많은 프로젝트에서 사용중인 오픈소스 프로젝트입니다.
본 포스팅에서는 npm
과 yarn
이 어떤 문제들을 해결하였으며, 이후 두 패키지 매니저의 발전 과정과 함께 yarn berry
에 대해서 소개하겠습니다.
yarn
이 등장하기 전, 과거의 npm
에는 다음과 같은 여러 문제가 있었습니다.
노드 모듈들은 기본적으로 시멘틱 버저닝이라는 기법을 사용하여 모듈들의 버전을 나타낼 것을 권장하고 있습니다.
여기서 시멘틱 버저닝이란 간단히 말해 1.2.3
처럼 버전을 세 가지 숫자가 들어갈 수 있는 자리로 구분하고, 각각의 자리에 현재 버전이 이전 버전과 어떤 관계가 있는지 암시하도록 하는 방법입니다.
그러나 이 방식은 장점과 동시에 단점을 함께 가지고 있습니다.
위 사진을 보면 모듈의 버전에 사용되는 캐럿 기호(^)
는 가장 앞 숫자인 메이저 버전을 제외한 두 자리 버전까지는 변경을 허용할 수 있다는 의미입니다.
즉, 현재 사용되는 react
는 ^18.2.0
이므로, 메이저 버전인 18이 변경되지 않는 범위에서는 모듈의 버전이 바뀌는 것(^18.3.0
or ^18.4.0
)을 허용합니다.
이는 빌드에 따라 유연하게 버전을 선택할 수 있다는 장점도 있지만, 이럴 경우 사용하는 모듈간의 버전 불일치로 인해 문제가 발생할 수도 있는 단점이 존재합니다.
즉 서로 다른 환경에서 하나의 프로젝트를 개발 한다는건 어떤 문제가 발생할지 모르는 잠재적인 위험을 안고 가는 것과 같습니다.
말 그대로 개발자의 환경에 따라 모듈들의 설치 순서가 변경될 수 있습니다.
이미 만들어진 프로젝트에서 모듈을 추가로 설치하게 될 경우, npm
은 모듈 이름을 사전 순서대로 정렬하여 순차적으로 설치하기 때문에 모듈 설치 순서가 달라질 수 있습니다.
즉 이런 상황 역시 앞서 말했던 것 처럼 서로 다른 환경이 만들어지기 때문에 잠재적인 위험성을 내포하고 있습니다.
npm
은 모듈들을 한 번에 하나씩만 순차적으로 설치합니다.
그래서 설치하는 모듈의 갯수가 많을수록, 총 설치 시간이 길어지게 됩니다.
이는 첫 모듈 설치 시간이 길어짐에 따라 빌드 또는 배포 시간에도 악영향을 끼치게 됩니다.
yarn
은 위의 문제들을 해결함과 동시에, 여러가지 기능들을 함께 탑재하여 등장하였습니다.
대표적으로 다음과 같은 기능들이 포함되어 있습니다.
yarn
은 사용할 모듈의 버전을 지정하기 위해 프로젝트에 .lock
파일을 포함합니다.
.lock
파일은 정확한 버전을 지정하여 다른 사용자가 프로젝트 개발시 항상 같은 버전의 모듈을 사용할 수 있도록 환경을 보장합니다.
이를 통해 기존 npm
의 일관적이지 않은 패키지 버전 문제를 해결할 수 있습니다.
yarn
은 패키지가 제대로 설치되었는지 확인하기 위해 checksum
을 사용합니다.
checksum
은 제대로 설치되지 않은 경우를 대비해 패키지 파일의 무결성을 확인하는 안전장치입니다.
yarn.lock
파일을 확인해보면 resolved
주소 뒤에 해시값이 추가 되는데 이 값이 바로 checksum
입니다.
개인적으로 체감한 yarn
의 가장 큰 장점은 속도입니다.
yarn
은 캐시를 사용하여 한 번 다운로드 한 패키지라면 이후 재설치시 더 빠른 속도로 설치할 수 있습니다.
이는 인터넷이 연결되지 않은 환경에서도 보장되며, 병렬 다운로드 또한 지원하기에 순차적 설치를 사용하는 npm
과 달리 한번에 많은 모듈들을 설치할 수 있습니다.
현재는 많은 시간이 지나 yarn
, npm
두 패키지 모두 많은 부분이 개선되었습니다.
특히 npm
은 버전 고정을 위한 package-lock
파일이 자동 추가되고, 속도 측면에서도 yarn
과 큰 차이가 없는 수준까지 개선되었습니다.
node_modules
또한 결정적(deterministic)
인 트리 구조로 만들 수 있게 되었습니다.
하지만 여러 발전을 거친 두 패키지 매니저 프로그램들에게도 여전히 남아있는 문제점들이 있었습니다.
npm
의 node_modules
폴더는 다음과 같이 큰 용량을 차지합니다.
용량을 줄이는 가장 간단한 방법은 중복을 제거하는 것입니다.
npm
과 yarn
은 node_modules
내부의 중복된 패키지를 최소화하기 위해 각 패키지가 의존하고 있는 패키지들을 최상단으로 끌어올려(hoisting)
버립니다.
이렇게 되면 프로젝트가 의존하고 있는 패키지의 내부에 존재하던 각각의 node_modules
에 있는 중복된 패키지가 최상단에 하나만 존재하게 되어 불필요한 중복을 제거할 수 있게 됩니다.
하지만 이 방법은 설치한 패키지가 의존하고 있다는 이유만으로 그 패키지까지 함께 불러올 수 있습니다.
이렇게 설치한 적이 없지만, 함께 호이스팅되어 최상단에 패키지가 존재 하는 문제를 유령 의존성 현상
이라고 합니다.
이 외에도 비효율적인 설치, 의존성 검색 등 많은 문제가 해결되지 않아 yarn
은 해당 문제를 어느정도 해결한 v2를 공개했습니다.
yarn berry
는 yarn
v2 이상의 modern version yarn
을 이르는 명칭으로 기존 문제점을 해결하기 위해 아래와 같은 기능들을 제공합니다.
Plug'n'Play
는 yarn berry
가 제공하는 새로운 패키지 관리 시스템입니다.
기존의 무거웠던 node_modules
대신, 패키지들에 대한 정보는 .zip
파일로 압축하여 .yarn/cache
폴더에 저장하고 이를 찾기 위한 정보를 .pnp.cjs
파일에 기록합니다.
그래서 별도의 I/O 작업 없이도 패키지의 위치를 정확히 알 수 있어 시간이 단축되고, 중복 설치를 방지합니다.
또한 node_modules
를 만들고 패키지들을 호이스팅시킬 필요가 없는 Plug'n'Play
의 특성 덕분에 앞서 말한 유령 의존성 문제도 해결할 수 있습니다.
yarn berry
를 통해 만든 의존성 폴더는 특수한 경우를 제외하면 200mb를 넘지 않습니다.
그래서 git clone
이후 별도의 설치 과정을 생략한 뒤 바로 사용하는 zero-install
을 시도할 수 있습니다.
zero-install
을 사용할 경우 CI/CD
파이프라인을 구축한다면 git clone
이 끝나자마자 바로 빌드가 가능하기에 배포까지의 속도를 상당 시간 감소시킬 수 있습니다.
npm shrinkwrap 으로 의존성 버전을 고정시키기
Yarn is Micro Secure
node_modules로부터 우리를 구원해 줄 Yarn Berry - toss tech 박서진님