Yarn2 (Yarn berry)
Yarn2
yarn vs npm
npm의 문제점
- lock 파일이 없다보니 생기는 패키지의 버저닝/의존 이슈
- 패키지 설치 순서에 따라서 디바이스, 환경마다
node_modules
트리가 다를 수 있다.
- 패키지 설치 순서에 따라서 디바이스, 환경마다
- 안정성/보안 이슈
- 패키지가 설치될 때 자동으로 코드와 의존성을 실행할 수 있도록 허용된다.
- 검증되지 않은 패키지가 포함될 수 있다는 위험성이 존재한다.
- 패키지가 늘어날수록 성능 저하
yarn
- yarn.lock 파일 자동생성, checksum을 통해 어느 환경에서든 동일한 패키지를 설치한다.
- yarn.lock에 있는 패키지를
설치만
한다.- 추가적으로 실행되는 코드나 의존성이 없어 안정성이 상대적으로 높다.
- 병렬 설치로 속도를 높였다.
- 내부적으로 mutex를 사용 해 다수의 CLI 실행 시 충돌하거나 오염시키지 않도록 방지한다.
- cache directory를 통한 오프라인 미러링
- 처음 빌드 할 때 레지스트리에서 다운로드한 파일을 로컬 캐시에 저장한다.
- left-pad 이슈 방지
- npm 레지스트리뿐만 아니라 Bower 레지스트리도 확인한다.
기존 패키지 관리의 문제점
1. 거대한 node_modules
- 파일 시스템(
node_modules
)을 이용하여 의존성을 관리한다.- 특정 라이브러리 패키지를 찾기 위해 계속 상위 디렉토리의 폴더를 탐색한다.
- 결과가 패키지의 상위 디렉터리 환경에 따라 달라질 수 있다.
- 패키지를 찾지 못하면 readdir, stat과 같은 느린 I/O 호출이 반복된다.
- 특정 라이브러리 패키지를 찾기 위해 계속 상위 디렉토리의 폴더를 탐색한다.
node_modules
디렉토리 구조는 매우 큰 용량을 필요로 한다.
2. 유령 의존성 (Phanthom Dependency)
- npm과 yarn1 에서는 중복해서 설치되는 문제를 해결하기 위해 끌어올리기(hoisting) 기법을 사용한다.
- A(1, 0), B(1, 0) 이 겹친다. 디스크 공간을 아끼기 위해 왼쪽 > 오른쪽 모양으로 바꾼다.
- 오른쪽으로 바뀌면서 B(1, 0)을 require 할 수 있게 된다.
- 이렇게 직접 의존하지 않는 라이브러리를 require 할 수 있는 현상을 유령 의존성이라고 한다.
- package.json에 정의 하지 않은 라이브러리를 조용하게 사용할 수 있지만, 다른 의존성을 제거했을 때 소리없이 같이 사라지기도 한다.
- 이런 특성은 의존성 관리 시스템을 혼란스럽게 만든다.
Yarn2
- yarn2 에서는 위의 문제점들을 해결하기 위해 몇 가지 방법을 고안해냈다.
ZipFS (Zip Filesystem)
- yarn2에서 패키지 설치 시
node_modules
에 디렉터리 구조를 그리는게 아니라, -
.yarn/cache
하위에 ZIP 파일로 저장된다.
- ex)
recoil@0.1.2
>recoil-npm-0.1.2-9a0edbd2b9-c69105dd7d.zip
yarn install
실행 시, zip파일을node_modules
하위에 압축 해제한다.- 장점
node_modules
디렉토리 구조를 그릴 필요가 없다. > 설치 빨라짐- 각 패키지는 버전마다 하나의 zip만 가져서 중복 설치를 방지한다. > 설치 용량 감소
- zip 파일이 변경되면 checksum으로 비교하여 변경을 감지한다.
- 의존성을 구성하는 파일의 수가 많지 않으므로, 변경 사항 감지, 삭제 작업이 빠르다.
- 패키지를 탐색하는데 사용하는 연산들이 감소한다.
Offline-cache
- 의존성도 git 등을 이용하여 버전 관리를 하면 어떨까? > 버전 관리에 포함하자!
.yarn
디렉토리를 레포지토리에 추가하면, 의존성을 설치할 필요가 없이 레포지토리를 클론해서 바로 쓰면 된다.
Pros
- 새로 저장소를 복제하거나 브랜치 변경 시 remote registry에서 패키지들을 받아오지 않는다.
- 여러 환경, 디바이스에서 동일한 패키지 버전이 보장된다. > 유령 의존성 해결
- 단순 압축 해제만 하기 때문에 CI에서 의존성 설치 시간을 크게 절약 가능하다.
npm
서버가 다운 되더라도 zip 파일 압축 해제만 하면 되기 때문에 오프라인에서도 동작 가능하다.
Plug’n’Play (PnP)
a.k.a. Zero Install
- PnP는 꽂으면 바로 사용할수 있다.. 라는 의미라고 한다.
동작 방법
.pnp.cjs
에 의존성을 찾을 수 있는 정보가map
으로 기록된다.pnp.cjs
파일과 zip 파일을 런타임 시 링크 해준다.-
ex) 리액트는 .pnp.cjs 파일에서 다음과 같이 나타난다.
/* 패키지 이름: react 패키지 중에서 */ ["react", [ /* 패키지 버전: npm:17.0.1 버전은 */ ["npm:17.0.1", { /* 패키지 경로: 이 위치에 있고 */ "packageLocation": "./.yarn/cache/react-npm-17.0.1-98658812fc-a76d86ec97.zip/node_modules/react/", /* 패키지 의존성: 이 의존성들을 참조한다. */ "packageDependencies": [ ["loose-envify", "npm:1.4.0"], ["object-assign", "npm:4.1.1"] ], }] ]],
- Zero Install이라는 말에 걸맞게
node_modules
폴더가 없다! - pull이나 clone시에 패키지를 설치 할 필요 없이 바로 실행 가능하다.
- 하지만…
- 호환성 테이블
- 런타임 시에 node가
import
,require
를 사용 할 때마다.pnp.cjs
를 연결해줘야 하는데, 라이브러리 제공자들이 PnP에서 지원할 수 있도록 제공해줘야 한다. - 지원하지 않는 패키지들은 커스텀 플러그인이나,
node_modules
플러그인과 함께 사용해야한다. - 또한 디버깅이 쉽지 않은 에러들 때문에 호불호가 갈린다.
- 이러한 리스크 때문에 보통 PnP는 제외하고 적용하는 듯 하다.
기타 yarn2의 새로운 기능들
- 플러그인 지원
- 워크스페이스 (모노레포)
patch
명령어 기본 지원- npm에 배포된 라이브러리 일부분만 수정 가능
yarn install
시 peerDependency에 등록된 css 패키지가yarn.lock
에서 사라져 매번 롤백해줘야 했는데, yarn2부터 개선되었다.
결론
- yarn2의 큰 특징은 1. Offline cache, 2. PnP 이다.
- Offline Cache는 패키지들이 ZIP으로 관리 돼 안정성과 속도 개선의 이점이 있어 적용해봄직 하다.
- PnP는 아직 지원도 적고 관리가 어려워 보여 도입이 어려울 것 같다.
- 또한 지원 버전도 낮은 편이 아니라, 기존 프로젝트보다는 새로운 프로젝트에 적용해보는게 좋을 것 같다.
pnpm
도 대체제로 많이 언급 되던데 리서치를 좀 더 해봐야겠다.