여러 기업들의 기술 블로그를 보다보면 많이 나오는 것들 중 하나가 'Yarn Berry'이다.
이번에는 Yarn Berry에 대해 알아보자
Yarn berry는 다양한 기업에서 사용하고 있다.
node_modules로부터 우리를 구원해 줄 Yarn Berry - 토스 ⭐️⭐️ 추천
yarn Berry workspace를 활용한 프론트엔드 모노레포 구축기 - 배민
리멤버 웹 서비스 좌충우돌 Yarn Berry 도입기 - 리멤버
모노레포 적용부터 yarn berry까지 - 화해 ⭐️⭐️ 추천
(yarn Berry 가 무조건 좋은건 아니다. 상황에 맞는 패키지를 쓰면 된다. 실제로 회사들도 하나의 패키지로 통일하지는 않는다.)
(ex 배민 스토어팀은 pnpm을 사용한다)
Yarn Berry 란?
(밑에서 상세히 다룸)
Yarn(yet another resource negotiator)은 facebook에서 빌드하고 google, Exponent 및 Tilde에서 지원하는 Javascript 패키지 및 종속성 관리자이다.
2016년 npm의 대안으로 처음 만들어졌다.
Yarn은 `Yarn classic`과 `Yarn Berry`가 있는데 `Yarn classic`은 `v1.x` 이고 `Yarn Berry`는 `v2` 이상이다. `yarn 2`라고 명명하는 곳도 있다.
패키지 매니저는 `yarn berry` 말고 대표적으로 `npm`, `pnpm`, `Yarn classic`이 있다.
`npm`은 2010년 `pnpm`은 2016년,`Yarn classic`은 2016년, `Yarn berry`는 2020년에 처음으로 발표되었다.
그렇다면 기존 개발자들은 npm을 주로 사용했을 텐데 왜 `Yarn classic`이나 `pnpm`등 대안이 생겨났을까 ? 무슨 문제가 있었던 걸까?
그전에 `NPM`에대해 먼저 알아보자
🚀 NPM
NPM(node pm or new pm)은 Node.js설치시 기본으로 제공되어 범용적으로 사용되어진다.
NPM을 사용하면 개발자가 패키지를 최신 버전으로 쉽게 업데이트하고 더 이상 필요하지 않은 패키지를 제거할 수 있다.
이렇게 하면 프로젝트를 체계적으로 유지하고 종속성을 최신 상태로 유지하는 데 도움이 될 수 있다.
🚨 NPM 의 단점
1️⃣ 보안 문제가 있다.
npm은 패키지를 중앙 집중식 저장소인 npm 레지스트리에 등록한다. 개발자들은 npm 레지스트리에서 패키지를 검색하고 필요한 패키지를 설치할 수 있다. npm은 패키지를 설치할 때, 레지스트리에서 해당 패키지를 다운로드하여 사용자의 프로젝트에 설치한다.
하지만 이렇게 중앙 집중식이기에 발생하는 보안 문제가 있다. 어떤개발자가 못된 생각을 해서 악성코드를 넣고 배포할 수도 있다.
2015년 엑스코드사건이 있었다. 엑스코드(Xcode)라는 애플의 앱 개발 툴의 하나인데, 이와 비슷한 엑스코드고스트(XcodeGhost)가 개발자들 사이에서 유포되기 시작한 것이다. 개발을 위해, 아무런 의심 없이 ‘비슷한 툴’을 다운로드 받은 개발자들은 자기들도 모르게 악성 앱을 만들어 앱 스토어에 올려놓게 되었고, 발견 당시 이미 39 종류의 앱이 감염된 상태였다. 해당 앱에는 사용자 풀이 대단히 넓은 위챗(WeChat)과 같은 것들도 포함되어 있었다. 관련 링크
left-pad 사건 관련 링크
2022년 유명 오픈소스 라이브러리인 colors가 오염된적이있다. colors의 개발자들이 악성 룹을 스스로 도입하였다. 이들은 오픈소스를 활용해 온갖 상업 행위를 하는 자들이, 오픈소스 커뮤니티에는 아무것도 베풀지 않은 것에 대한 복수로 이 같은 짓을 저질렀다고 한다.
colors는 1주일에 2천만 회 이상 다운로드 되며, 2만 여개의 프로젝트들이 이 colors를 사용하고 있다. 관련 링크
그나마 2017년 5월부터 npm v5 릴리스 때 패키지 매니페스트(`package.json`)와 `package-lock.json파일`(v5때 처음 도입)을 사용하여 패키지의 무결성을 보다 확실하게 체크하여 안정성을 높였고(`SHA-512 알고리즘` 사용) v6부터는 `npm audit` 기능을 도입하였다.
`npm audit`은 프로젝트의 종속성 트리를 분석하여 보안 취약점이 있는 패키지를 식별하고 보고서를 제공한다. 이를 통해 개발자들은 프로젝트에서 사용 중인 패키지의 보안 상태를 확인하고, 보안 취약점을 해결하기 위한 조치를 취할 수 있다.
2️⃣ 속도가 느리다.
npm은 종속성 패키지를 설치할 때 순차적으로 설치하기 때문에 엄청 큰 파일을 설치할 때 성능이 떨어진다.
3️⃣ 무겁다
예를 들자면 압축되지 않은 파일로 구성된 135,000개의 node_module 폴더는 총 1.2GB의 용량을 차지하는 반면 , Yarn 캐시는 2,000개의 바이너리 아카이브로 구성되어 총 139MB의 용량을 차지 한다.
4️⃣ 유령 의존성
`NPM`과 `Yarn classic`에서는 중복해서 설치되는 `node_modules`를 아끼기 위해 `Hoisting`기법을 사용한다.
예를 들어, 의존성 트리가 왼쪽의 모습을 하고 있다고 가정해보자.
왼쪽 트리에서 `A(1.0)`과 `B(1.0)` 패키지는 두 번 설치되므로 디스크 공간을 낭비한다. 때문에 NPM과 Yarn classic에서는 디스크 공간을 아끼기 위해 원래 트리의 모양을 오른쪽 트리처럼 바꾼다.
오른쪽 트리로 의존성 트리가 바뀌면서 package-1 에서는 원래 `require()` 할 수 없었던 `B(1.0)` 라이브러리를 불러올 수 있게 되었다.
이렇게 Hoisting에 따라 직접 의존하고 있지 않은 라이브러리를 `require()`할 수 있는 현상을 유령 의존성이라고 부른다.
유령 의존성 현상이 발생할 때, `package.json`에 명시하지 않은 라이브러리를 조용히 사용할 수 있게 된다. 다른 의존성을 `package.json`에서 제거했을 때 소리없이 같이 사라지기도 한다. 이런 특성은 의존성 관리 시스템을 혼란스럽게 만든다.
5️⃣ 비효율적인 의존성 검색
개발을 하다보면 라이브러리를 많이 사용하게 된다. 그러다 보면 의존성이 생기게 되는데
node.js는 그 의존성을 현재 경로부터 계속 상위 디렉토리로 이동하면서 필요한 의존성을 찾을 때까지 탐색한다.
예를 들어보자.
우리가 만약 `lodash`라이브러리를 사용한다고 해보자.
`npm i lodash`를 입력한 후 사용하기위해 `require("lodash")` 를 하면 바로 `/node_modules`에서 가져오는게 아니다.
이곳 저곳 다 뒤진다. 즉, 찾을 때까지 다 방문한다는 소리다.
실제로 찾는 경로를 보면 아래와 같다.
이러한 의존성 탐색 방식은 비효율적이다. 원하는 의존성을 탐색하기 위해 매번 수많은 File I/O를 발생시켜야 했다.
또한 디렉토리는 기본적으로 `Tree` 구조이다. 이는 `Linked List`의 탐색 특징을 가지고 있음을 의미하고 있다. 최악의 경우 O(N)만큼 탐색해야 원하는 값을 얻을 수 있음을 의미한다.
위와 같은 문제들을 일부 해결한 Yarn classic이 2016년에 등장한다.
🚀 Yarn classic
Yarn은 NPM과 유사한 JavaScript 프로그래밍 언어용 패키지 관리자이다. Facebook에서 개발했으며 NPM의 성능과 안정성을 향상시키는 것을 목표로 개발되었고 2016년에 처음 발표되었다. NPM과 마찬가지로 Yarn은 패키지를 관리하는 데 사용된다.
npm과 차별되는 Yarn의 특징
- offline Mode : 이전에 패키지를 설치했다면 인터넷 연결 없이 다시 설치할 수 있다.
- Deterministic : 설치 순서에 관계없이 동일한 종속성이 모든 시스템에 동일한 방식으로 설치된다.
- Network Performance : Yarn은 네트워크 활용도를 극대화하기 위해 효율적으로 요청을 대기열에 넣고 요청 워터폴을 방지한다.
- Network Resilience : 단일 요청이 실패해도 전체 설치가 실패하지 않는다. 요청은 실패시 자동으로 재시도된다.
- Flat Mode : Yarn은 일치하지 않는 종속성 버전을 단일 버전으로 해결하여 중복 생성을 방지한다.
- Secure : Yarn은 체크섬을 사용하여 코드가 실행되기 전에 설치된 모든 패키지의 무결성을 확인한다.
yarn classic은 2020년 부터 유지보수 모드로 전환되었다.
그리고 드디어 2020년 10월 Yarn Berry가 출시한다.
🚀 Yarn Berry
Yarn Berry는 Yarn 패키지 매니저의 새로운 버전으로, 이전 버전인 Yarn Classic과는 구조적으로 변화와 새로운 기능은 도입하였다.
특징
- Type Script
- 앞서말한 npm과 Yarn Classic와 달리 Yarn Berry는 TypeScript로 작성되어 완전히 타입 체크가 되어 있다.
- Plug'n'Play(Zero Install)
- Yarn Berry는 기존의 로컬 `node_module` 폴더 대신 패키지를 캐시 폴더에 저장하고, `.pnp.cjs`파일에 의존성을 찾을 수 있는 정보가 기록된다. `.pnp.cjs`를 이용하면 디스크 I/O없이 어떤 패키지가 어떤 라이브러리에 의존하는지, 각 라이브러리는 어디에 위치하는지를 바로 알 수 있다.
예를들어 , `prettier` 패키지는 `.pnp.cjs` 파일에서 다음과 같이 나타낸다.
/* prettier 패키지 중에서 */
["prettier", [\
/* prettier 패키지의 버전이 2.8.8이고 npm 패키지로 등록되어있다. */
["npm:2.8.8", {\
/* 이 위치에 있고 */
"packageLocation": "./.yarn/cache/prettier-npm-2.8.8-430828a36c-b49e409431.zip/node_modules/prettier/",\
/* 이 의존성들을 참조한다. */
"packageDependencies": [\
["prettier", "npm:2.8.8"]\
],\
/* 실제 파일 시스템에 복사된다.(해당 패키지가 모듈로 사용되는 모든 위치에서 동일한 내용을 가짐) */
"linkType": "HARD"\
}]\
]],\
'linkType' 은 .pnp.cjs 파일에서 각 패키지의 링크 유형을 나타내는 속성이다. 'HARD' 또는 'SOFT'가 있다.
"HARD" : 해당 패키지는 실제 파일 시스템에 복사된다. 이는 해당 패키지가 모듈로 사용되는 모든 위치에서 동일한 내용을 가지게 됨을 의미한다.
"SOFT" 해당 패키지는 심볼릭 링크로 연결된다. 이는 해당 패키지가 모듈로 사용되는 모든 위치에서 동일한 내용을 참조하게 됨을 의미한다. 따라서, 실제 파일이 변경되면 해당 모듈에도 변경 내용이 반영된다.
또한 yarn PnP모드에서는 의존성을 설치하는 시점에서 `Dependencies Mapping Table`같은 것을 만들고 이후에 의존성을 참조해야 할 경우에는 이 `Table`을 통해 참조할 위치를 얻어낸다.
`Table` 구조는 O(1)의 성능을 가졌을 뿐만 아니라 JSON데이터 타입을 사용하기 때문에 메모리 내의 연산이 이루어지게 되고 FIle I/O 보다 훨씬 좋은 성능을 보여준다. 여기다 PnP모드는 설치한 의존성을 압축하여 `.zip파일`로 관리할 수 있다. 이를 통해 스토리지 용량을 크게 아낄 수 있다. ( PnP에 대한 고찰은 이 링크글의 중간쯤에서 확인할 수 있다)
이제는 많은 유명 라이브러리들이 Plug'n'Play를 지원하고 있다. (호환성 표)
- Plugins
- Yarn berry는 플러그인 기능을 제공하여 사용자들이 기존 도구에 추가 기능을 쉽게 통합하고 사용할 수 있도록 한다.
- 플러그인은 Yarn berry의 기능을 확장하거나 사용자 정의 동작을 추가하는 데 사용된다.
- 커맨드 확장 : Yarn 명령어에 사용자 정의 명령어를 추가할 수 있다. 이를 통해 특정 작업을 자동화하거나 프로젝트의 특정 요구에 맞는 동작을 수행할 수 있다.
- 작업 흐름 개선 : Yarn의 작업 흐름을 개선하거나 사용자 경험을 향상시킬 수 잇는 기능을 추가할 수 있다. 예를들어, 프로젝트 빌드 전/후에 특정 작업을 실행하거나 테스트 도구와의 통합을 간소화할 수 있다.
- 보안 및 안정성 : 플러그인을 사용하여 패키지 무결성 검증, 취약성 스캔, 의존성 갱신 등과 같은 보안 및 안전성 관련 작업을 수행할 수 있다.
- 외부 도구 통합 : Yarn을 다른 도구와 통합하여 작업을 간소화하고 개발 과정을 향상시킬 수 있다. 예를 들어 IDE 통합 Git 훅 관리, 코드 포맷터 통합 등이 있다.
- 플러그인은 Yarn 커뮤니티에서 개발되고 공유되며, 사용자들은 필요한 플러그인을 선택하여 프로젝트에 통합할 수 있다.
마무리
1편은 여기까지다.
왜 기업들은 `Yarn Berry`를 많이 사용할까? 지금 내용만 가지고 답변하기는 힘들다. 더 추가적인 내용이 있다. 미리 스포를 하자면 `모노 레포`를 구축하는데 `Yarn Berry` 가 잘 어울리기 때문이다.
그럼 또 궁금해진다. 왜 기업들은 `모노 레포`를 사용하며 위에 있는 'Yarn Berry' 특징들 중 뭐가 마음에 들어서 `모노 레포`를 구축하는데 패키지 매니저로 사용했을까?
다음 글에서 작성하고자 한다.
Reference
NPM vs Yarn: Which package manager should I use?
https://github.com/npm/cli#is-npm-an-acronym-for-node-package-manager
Yarn vs NPM: Which Package Manager is Better?
Picking the best package manager. A 2023 comparison of npm, Yarn, and pnpm.
Yarn Berry: a next generation package manager - Michael Richardson - NDC Copenhagen 2022
.
'Node.js' 카테고리의 다른 글
[Node.Js] Module (1) | 2023.12.17 |
---|---|
Peer Dependencies는 왜 필요하고 사용될까? (0) | 2023.12.03 |
package.json (0) | 2023.10.08 |
패키지 매니저 비교 (npm vs yarn vs pnpm) (0) | 2023.08.20 |
yarn berry 세팅하기 (0) | 2023.07.02 |