home

yarn berry와 pnpm 둘 중 하나를 골랐습니다.

글 분류
main
키워드
pnpm
생성일
2022/07/22 13:56
최근 수정일
2025/02/13 01:26
작성중

⚽️ 목표

NPM vs Yarn Classic(v1) vs Yarn Berry(v2) vs PNPM
Yarn Classic과 Yarn Berry는 다르다는걸 인지하자.
현시점(2022년 7월 22일) 기준으로 Yarn Classic은 기능 추가 또는 개선없이 관리만 진행되는 중 이다.

TL;DR

PNPM
점점 패키지 매니저들의 차이점이 희미해진다.
pnp도 yarn berry, pnpm 둘다 있다.
pnpm의 CAS를 yarn berry에서 채용하기로 확정했다.
npm은 보안적으로 허점이 있었었다(과거 완료형)
현재는 여러 방법(패키지 등록시 취약점 검사와 같은)으로 대응 완료됨.
yarn berry의 pnp(plug and play)는 이슈가 많다.
현재 회사 프로젝트 기반으로 복잡하지 않게, 간단하게 “실행되냐?”의 기준으로 봤을때… 스토리북 부터 해서 많은 오류가 발생했다.
기존 구성된 npm 프로젝트에서 pnpm으로 이주 시 생긴문제 단 하나였다.
storybook 관련 이슈였지만 아주 마이너한 이슈였다. → hoisting 되지않은 패키지로 인한 이슈였다. 해당 패키지를 간단하게 설치만해주니 완전 정상작동하였다.
pnpm도 설정으로 pnp 활성화가 가능하다.
더욱더 yarn berry를 선택할 이유가 희미해진 계기다. yarn berry가 이제는 나에게 “굳이?”라는 관점으로 다가왔다.

1-1. npm과 Yarn classic(Yarn v1)

npm

“여러분 NPM은 Node Package Manager의 약자가 아닙니다” - 공식문서
2010년에 출시
NPM 이름은 Node Package Manager가 아닌 Node PM, New PM을 뜻한다.
처음엔 여러 이슈들이 있었으나 대부분 해결 된 상태
lock 파일의 부재 → 설치할 때마다 조금 씩 바뀌는 버전들로인한 프로젝트 안정성 저하, 지금은 lock 파일 지원
패키지 관리자의 시작
이전 JS 생태계에선 패키지를 모두 수동으로 설치 및 관리 했었다.
npm의 등장으로 인해 패키지 출시 및 관리가 편의해진건 부정할 수 없는 사실이다.

Yarn classic (Yarn v1)

Yet Anoter Resource Negotiator
2016년에 페이스북 + 구글 + 기타등등이 출시한 새로운 패키지 관리자
npm과 똑같은 의존성 해결 방식을 채택함 → 여전히 비효율적인 패키지 의존성관리
출시 당시엔 npm에 비해 상대적으로 좋은 성능으로 관심을 받았었다. → 요즘은 npm이나 yarn v1이나.. 둘다 비슷비슷하다.
.lock 파일의 존재를 처음으로 만들었다. → 이후엔 npm에서도 .lock 파일을 제공
2020년 부터 maintenance mode가 됨 → 추가 기능 개발 없이 관리만 진행

yarn과 npm의 문제점

node_modules를 이용해 dependency를 관리한다.
중복된 똑같은 dependency가 많아→ 저장공간을 많이 차지하며 어쩔땐 같은 라이브러리를 메모리에 중복되게 인스턴스화 한다.

요즘은?

서로의 장점을 도입하고 변화해가면 사실상 npm과 yarn v1의 차이점은 크게 존재하지 않는다. 속도 대결 또한 엎치락 뒤치락.

1-2 pnpm

pnpm의 컨셉 사진

npm, Yarn v1의 평탄화된 node_modules

npm과 yarn classic은 중복된 라이브러리를 “그나마" 줄이기 위해 평탄화(으.. 군대용어)를 수행함
flattened를 평타화로 번역했다. 어떻게든 번역하려 노력하는 내 자신이 조금 싫어졌다.
// 평탄화 전 라이브러리A/node_modules/libName 라이브러리B/node_modules/libName // 평탄화 후 라이브러리A 라이브러리B libName
Plain Text
복사
라이브러리 A, B 둘다 libName이란 패키지에 의존성을 가지고 있다.
A, B 각자의 node_modules 아래에 라이브러리을 가지고 있을 경우 디스크 공간의 낭비!
라이브러리 1을 라이브러리 A와 B와 같이 루트 디렉터리로 호이스팅 한다! →A와 B는 호이스팅된 1을 참조
그렇다. 여기서도 호이스팅이 존재한다. 누가 JS 패키지 관리 툴 아니랄 까봐 호이스팅도 똑같이 따라한다.
이로인해 유령 의존성이 생긴다. → 내가 설치하지 않은 라이브러리를 참조할 수 있게 되는 마법이 생기는것이다.

content addressable store

hardlink, softlink가 뭐에여?
모든(서로다른 프로젝트) dependency는 하나의 파일을 참조한다.
사용자의 홈디렉터리 아래(~/.pnpm-store) 존재하는 저장 장소를 칭한다.
결과적으로 모든 dependency들은 CAS를 바라보고 있다, 같은 버전일 경우 똑같은 파일을 굳이 같은 파일을 또 설치하는게 아니라 CAS에 존재하는 파일들을 연결시켜주는 개념이라고 보면된다.

non-flat node_modules 디렉터리

pnpm 공식 홈페이지에 존재하는 non-flat node_modules 디렉터리
pnpm은 기본 옵션으로 평탄화되지 않은 node_modules 디렉터리 구조를 만든다.
물론 친절한 pnpm으로 옵션으로 평탄화된 node_modules를 사용할 수 도 있다.
설정 이름이 shamefully-hoist다. 본인 생각해도 flatten된 node_modules를 쓸거면 굳이 pnpm을 써야하나? 라는 생각이다. 부끄러워하십시오. 휴먼. 이라는 느낌을 지울 수가 없다.
# pnpm 프로젝트 /node_modules - 라이브러리 A (.pnpm과 symlink 되어있음) - .pnpm - 라이브러리 A (라이브러리 A의 hardlink된 파일)
Bash
복사
기본 설정으로는 평탄화가 수행되지 않아 유령 의존성이 아예 사라진다.
프로젝트의 node_modules에는 실제 파일이 아닌 각자 필요한 참조를 softlink로 연결 후 파일은 hardlink 시켜준다.

평탄화를 없애기위한 pnpm의 노력

npm, yarn이 가지고 있던 비효율적인 의존성 관리 방식을 해결 → content-addressable storage를 이용
npm, yarn은 실제 의존성 파일들은 node_modules에 존재하나 pnpm은 사용자의 홈디렉터리 아래(~/.pnpm-store)에 실제 dependency들을 저장 → pnpm의 node_modules들은 .pnpm-store로 링크로만 존재한다.
유령 의존성이 존재하며 실제 중복 파일들이 많이 존재하는 NPM의 node_modules보다 적은 용량 차지, 메모리에 중복된 인스턴스로 존재하지 않는다.

서로 닮아가는 패키지 관리자

yarn berry → content-addressable storage 도입 예정
npm → symlink를 활용한 node_modules 방식 도입 예정
pnpm → pnp 지원
사실상 다 거기서 거기가 되어가고 있다.

1-3 Yarn berry

2020년에 릴리즈 → 기존 Yarn과 전혀다른 코드베이스

PnP(Plug n Play)

다른 관리자들과 다르게 node_modules대신 .pnp.cjs를 생성 한다.
중첩된 node_modules와는 다르게 하나의 파일로 존재
의존성 검색이 효율적으로 수행됨 → 빨라짐
중첩된 파일구조인 node_modules를 순회하며 찾을 필요가 없다. → .pnp.cjs에 실제 패키지 저장 위치 바로 참조가능
package를 검색한 후 거의 즉각적으로 페이지를 찾아갈 수 있게 됨
실제 패키지들은 프로젝트 디렉터리에 .yarn/cache/에 zip 파일로 존재 → 디스크를 차지하는 용량이 더줄어듬
pnpm과 같이 의존성 호이스팅이 이루어지지 않아 유령 의존성이 사라짐

Zero Install

기존 npm과 다른 패키지 관리자들은 브랜치를 바꾸거나 리포지터리를 당겨왔을 때 npm i, yarn install로 패키지들을 설치 → node_modules가 너무 무거웠기 때문에 리포지터리에 같이 업로드 불가
Yarn berry에서는 패키지가 zip 파일로 압축되어 존재하기 때문에 용량이 현저히 낮으며 + 중복된 패키지가 최소화됐으므로 기존 node_modules에 비해 용량이 매우 낮다 → 리포저터리에 업로드하여 사용 가능
브랜치를 바꾸거나 리포지터리를 새로 당겨왔을 때 install 없이 바로 사용 가능

2. Yarn berry 설치

Yarn 개발 개발진의 추천 → node 설치 시 함께 설치되는 corepack을 이용해 설치, 굳이 복붙할 필요성을 못느껴서 공식문서 태그…!
corepack이 뭐에요?

3. node_modules가 설치될 경우

nodeLinker

실제 사이드 프로젝트에 yarn berry 이주 테스트를 진행했으나 node_modules가 남아있…다? 그거 없다고 자랑한거 아니였어?
홈디렉터리에 존재하는 .yarnrc.yml에 nodeLinkder: node-modules 부분을 제거(또는 pnp로 변경후 yarn install로 다시설치!
아-기다리고-기다리던 pnp.cjs 파일이 생성되는걸 드디어 확인할 수 있음

vite dev 모드 시작 시 생기는 node_modules

vite에서 제공하는 Dependency Pre-Building 기능
개발 모드에서만 사용되며 의존성 패키지들을 미리 전처리 → 빠른 속도를 위해

기타

zero-install시 git-ignore 사항

결론

요즘 패키지 관리자들은 서로 닮아가고 있는 중. 그럼에도 불구하고 pnpm, yarn berry 중 하나 골라 쓰면 좋을거같다.
아직 지원하지 않는 라이브러리(PnP, ZeroInstall) 때문에 아직까지 호환성 이슈가 존재(VSC... VSC... VSC, Storybook)
프로젝트에서 이주 시도 시 직접 마주친 문제만 5개정도 - 그에 반해 pnpm은 사소한 이슈 1개 정도?
Zero Install의 필요성을 잘느끼지 못했다. -> 오히려 pnpm의 content-addressable storage가 더 매력적으로 느껴졌음
pnp 기능은 pnpm에서도 옵션으로 활성화 가능하다.
본인은 pnpm으로 가겠다.

참조