Yarn2.0과 pnpm을 사용하는 이유

d_wwan·2023년 10월 11일
0

🚨 yarn1.0, npm의 demerit

1. Security

중앙집중식 레지스트리를 보유한 npm은 나쁜 의도를 가진 개발자가 악성 코드를 패키지에 담는다면 설치 시 보안문제가 발생할 수 있다. ( 놀랍네... )

Ghost Xcode 사건
https://www.boannews.com/media/view.asp?idx=56184&kind=1

물론 패키지 매니페스트(package.json)와 package-lock.json파일(v5때 처음 도입)을 사용하여 패키지의 무결성을 보다 확실하게 체크하여 안정성을 높였다고한다.

2. 속도

이전 글에서 설명했던 것 처럼 npm은 패키지를 순차적으로 설치하기에 느릴 수 밖에 없다. 이 점도 많이 개선되었다고는 한다.

3. 용량

yarn 1.0과 npm은 둘 다 Ghost Dependency에 의한 용량 문제를 갖고 있는데 이는 설치 시 발생하는 문제를 해결하기 위해 Hoisting기법을 사용해 나타나는 또 다른 문제다.

npm과 yarn은 node_modules 내부의 중복된 패키지를 최소화하기 위해 각 패키지가 의존하고 있는 패키지들을 최상단으로 올린다.

이렇게 되면 프로젝트가 의존하고 있는 패키지의 내부에 존재하던 각각의 node_modules에 있는 중복된 패키지가 최상단에 하나만 존재하게 되어 불필요한 중복을 제거할 수 있게 된다.

But

내가 설치한 패키지가 의존하고 있다는 이유로 그 패키지까지 불러오게 된다. 나는 설치한 적이 없지만, 그 패키지는 최상단에 존재 하고 있다.
이러한 현상을 유령 의존성이라고 부른다.


🐈‍⬛ Yarn 2.0 의merit

PNP

Plug'n'Play는 yarn berry가 제공하는 새로운 패키지 관리 시스템이다.

기존의 무거웠던 node_modules 대신, 패키지들에 대한 정보는 .zip 파일로 압축하여 .yarn/cache 폴더에 저장하고 이를 찾기 위한 정보를 .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"]
    ],
  }]
]],

별도의 I/O 작업 없이도 패키지의 위치를 정확히 알 수 있기 때문에 시간도 단축되고, 중복 설치를 방지하며, node_modules를 만들고 패키지들을 호이스팅시킬 필요가 없는 Plug'n'Play의 특성 덕분에 유령 의존성 문제도 해결할 수 있다.

Zero install

github는 파일당 최대 용량을 500mb으로 제한하고, 원활한 이용을 위해 저장소당 1gb 미만의 크기를 유지 할 것을 권장하고 있다.

yarn berry를 통해 만든 의존성 폴더는 어지간히 크지 않은 이상 200mb를 넘지 않는다. 덕분에 git clone 이후 별도의 설치가 필요 없이, 바로 사용할 수 있도록하는 zero-install을 시도해 볼 수 있다.

zero-install을 사용할 경우 로컬에서의 귀찮음도 줄어들지만, CI/CD 파이프라인을 구축한 경우 더 큰 효과를 볼 수 있다. 클론이 끝나자마자 곧바로 빌드가 가능해진 덕분에 배포까지 걸리는 속도가 대폭 단축된다.

이러한 장점들로 큰 기업에서 진행하는 큰 프로젝트에서 npm, yarn classic과 비교해 빌드를 1분 정도 줄일 수 있다고 한다.

성능 예시
https://blog.hwahae.co.kr/all/tech/11962

But...

캐시가 없을 땐 pnpm더 빠르다!

새로운 의존성을 설치할 때는 pnpm이 훨씬 빠르다는 이야기다.

그렇다면 yarn 2.0이 아닌 pnpm을 사용해야하는 이유는 무엇이 있을까?

yarn berry의 단점?

1. git에 주는 부하
작업한 뒤 커밋을 하면 .git/objects 내에 변경된 파일이 zlib으로 압축되어 영구히 기록으로 남는다. 기업에서 진행하는 큰 프로젝트의 경우 많은 양의 커밋이 부담이 될 수 있다.

2. 모든 의존성들이 pnp로 관리되지는 않는다.

로컬 환경의 의존성을 가지는 모듈들은 zip 파일로 관리되지 않고 unplugged라는 디렉토리 내 별도의 바이너리 파일로 관리된다.

이러한 단점들은 프로젝트가 비대할 시 일어나는 특징들이기 때문에 현재의 내가 경험하기엔 어렵다.

일단 npm을 절대 써서는 안된다는건 진짜로 알았다. 이제 yarn2.0과 pnpm 중 하나를 선택하기 위해 pnpm을 사용해야 하는 이유를 알아보자.


📀 pnpm의 merit

https://pnpm.io/ko/next/feature-comparison
pnpm과 yarn의 기능 비교

pnpm의 속도

https://velog.io/@king6624/npm-yarn-pnpm
pnpm의 링크 구조에 대해선 저번에 작성했다!
이런 구조 덕분에 속도와 용량에 큰 장점이 있다.


만약 pnpm add express를 실행하게 된다면 node_modeules/에는 express만 설치되고 express에 필요한 의존성들은 .pnpm store에 저장된다.

Content-addressable-memory

매우 빠른 속도를 요하는 탐색 애플리케이션에서 사용되는 특수한 메모리
주소에 의해 접근하지 않고, 기억된 내용의 일부를 이용하여 접근할 수 있는 기억장치
보통 CAM으로 줄여 말하며, 연관 메모리(associative memory), 연관기억장치라고도 한다.

pnpm을 사용하면 의존성이 content-addressable 저장소에 저장되므로, 하나의 의존성파일만을 갖게됩니다.

모노레포에서의 강점

모노레포는 쉬운 코드 재사용, 간단한 의존성 관리, atomic 커밋(커밋할 때마다 모든 것이 함께 작동, 변경 사항의 영향을 받는 곳에서 쉽게 변화를 탐지), 큰 스케일의 코드 리팩토링, 팀 간의 협업, 테스트 빌드 범위 최소화 등을 멀티레포 보다 쉽게 가능하게 해준다.

그럼 npm과 yarn보다 모노레포에서 뭐가 더 편한가 ? (라이브러리 제외)

monorepo를 위한 명령어가 존재하기 때문이다.

Dockerfile monorepo build를 위해 RUN fetch 명령어를 사용하여 하위 폴더에 있는 package.json을 설치한다든지 등 monorepo만을 위한 명령어가 존재하기에 npm,yarn보다 수월한 build 및 사용이 가능하다.

profile
세상 모든 사람들을 이해할 수 있는 날이 오기를

0개의 댓글