본문으로 바로가기

TIL 2022-03-02 pnpm, yarn berry, pnp

category TIL 2022. 3. 2. 22:31
npm

Node.js에서 사용하는 가장 유명한 패키지 매니저는 npm이다.

 

동일한 패키지의 다른 버젼을 사용하는 패키지들을 사용하는 경우

이런 의존성을 가지게 되는데, 중복된 하위 패키지를 가지면 용량 면에서나 depth 면에서나 문제가 생겼다. 긴 경로 같은 경우 문자수제한이 있는 Windows같은 경우에는 문제가 생겼다.

 

npm v3에서는 플랫하게 올릴 수 있는 패키지 같은 경우는 최상단으로 올리는 방식으로 depth 문제를 어느 정도 해결하엿으나 설치 순서에 따라 의존성 트리가 달라지는 문제가 있었다.

 

트리가 non-deterministic한 형식으로 생성된다는 뜻이다.

 

 

 

이런 형식의 의존성 트리를 구성한 프로젝트에서

로 모듈 A를 업데이트한다고 하자

 

그러면 결과적으로는

프로젝트는 이러한 의존성 트리를 갖게 된다.

 

만약 이것을 테스팅 서버로 넘기면

테스팅 서버는 이러한 형식의 의존성 트리를 갖게 되는데,

 

이는 설치 순서에 따라서 트리가 구성되는 방식이 다르기 때문이다. 테스팅 서버로 받은 package.json에서는 기존의 node_modules가 없기 때문에 A v2.0가 포함되어 있다. A의 종속된 B v2.0은 최상단으로 끌어올려지는 최우선순위이기 때문에 E에 속해있는 B v1.0은 끌어올려지지 않는다.

 

이것이 문제가 되지는 않는다고 npm 문서에는 적혀져있는데, 다른 구성으로 되어있는것 자체가 굉장히 불쾌하긴 하다.

 

 

yarn
  • 의존성 트리가 다름
  • 느림
  • lock 파일을 수동 설치해야함(npm v5부터는 자동으로 생성)

 

등의 문제를 해결하기 위해 나왔다.

 

 

npm에서는 순차적으로 패키지를 설치하는 것을 yarn에서는 병렬 설치를 통해 시간을 단축시켰고 오프라인 미러를 통해서 npm에서 생겼던 left-pad 문제등의 문제를 어느정도 방지할 수 있다.

 

yarn는 패키지 레지스트리 서버에서 패키지를 가져올떄 tgz로 가져와 이를 node_modules에 압축을 풀어준다. offline-mirror는 압축을 해제하기 전 상태로 보관하는 저장소다.

 

offline-mirror가 있다면 어떠한 이유로 해당 패키지 레지스트리 서버에 접속이 불가능하더라도 offline-mirror에 접근해 패키지를 풀 수 있게 도와준다.

 

pnpm

 

yarn npm 둘다 해결할 수 없는 문제점들이 있었는데

  • 직접 의존하지 않는 라이브러리들 사용 가능 (Phantom Dependencies)
  • 의존성 트리 플랫화 알고리즘이 복잡함
  • 캐시에서 프로젝트의 node_modules에 복사되어야함

이러한 문제점을 해결하기 위한 것이 pnpm이다.

 

pnpm는 npm v2처럼 각 라이브러리가 각각 node_modules를 가지는데 대신 symbolic link를 사용하여 완전히 플랫한 구조를 만들었다.

 

react 16을 dependency로 갖는 react-16-package와 react 17를 dependency로 갖는 react-17-package가 있을떄 pnpm로 나타내면 이렇게 된다.

node_modules
  - .pnpm
    - node_modules
      - react 16
      - react 17
      - react-16-package
        - node_modules/react 16 (symlink → ../../react 16)
      - react-17-package
        - node_modules/react 16 (symlink → ../../react 17)
  - react-16-package (symlink → ../.pnpm/node_modules/react-16-package)
  - react-17-package (symlink → ../.pnpm/node_modules/react-17-package)

 

또한 pnpm/node_modules의 패키지 파일들은 원본이 아니라 ./pnpm-store의 패키지 파일들의 hard link라

 

만약 저장소에 100개의 레포가 있을때 100개의 레포에서 동일한 라이브러리를 사용한다고 하면 pnpm-store라는 모듈 저장소에 한번만 저장을 하고 레포지토리에는 이에 대한 hard link만을 제공해주는 것이다. 아이 가벼워~

 

확실히 비교를 해보면 pnpm이 성능적으로 이점이 있으나 동일 파일 시스템에서만 사용하는 hard link로 인해

 

C 드라이브에서 되던게 D 드라이브에서는 안될 수도 있고,

hard link/ symbolic link를 지원하지 않는 파일 시스템도 존재하고

파일 감시툴인 watchman에서 동작하지 않는다.

 

 

hard link와 symbolic link는 이런 느낌이다.

 

inode는 파일 내용의 주소를 가지고 있고, 원본 파일이나 하드 링크나 이 inode를 바라보고 있다.

따라서 원본 파일이 사라져도 하드링크에서는 inode에 접근 할 수 있기 때문에 파일 내용이 보존 가능하다.

 

심볼릭 링크는 원본 파일의 주소를 가리키는 링크다. 따라서 원본 파일이 지워지면 심볼릭 링크에서는 해당 파일 내용에 접근할 수 없게 된다. 마치 바로가기 파일은 원본이 삭제되면 접근할 수 없는 것처럼 말이다.

 

운영체제에서 배운게 나오다니 재밌다.

 

Yarn berry

 

PnP(Plug'n'Play)라는 메커니즘을 통해 기존의 문제점을 해결하려고 했다.

 

Node.js에서는 모듈 사용할때 부모->루트까지 node_modules를 찾는 방식을 사용하는데 시스템 함수를 호출함에 따라 런타임에 시작 속도 저하가 일어남

 

Yarn에서는 원격 저장소 -> 오프라인 미러 -> 캐시 -> 캐시 패키지를 node_modules에 복사 라는 과정을 거치는데 I/O 연산이 비싸다.

 

node_modules 자체가 중복 제거도 완벽치 못하고 실용적이지 않다

 

Node.js는 패키지란 개념을 모르기 때문에 Phantom Dependency 발생

 

이를 해결하기 위해 .pnp.js라는 파일을 생성하여

 

  • 의존성 트리에서 어떤 파일을 사용 가능한가
  • 패키지들 간의 연결
  • 디스크에서 어디에 위치하였는가

 

등의 내용을 담고 이를 통해 모듈 처리 방식을 구성한 resolver를 갖는다.

 

또한 node_modules를 갖지 않고 yarn/cache에 패키지를 zip 형식으로 저장하여이 경로를 pnp.js에 명시함.

 

따라서 pnp.js를 통해 훨씬 빠르게 패키지를 설치 및 실행하며 관련 패키지들이 모두 명시되어 있기 때문에 각 패키지도 최상단으로 끌어올려짐.

 

 

내가 참조한  2019년 당시 작성된 글에서는

 

이렇게 npm과 berry의 속도 차이가 별로 나지 않았었다.

 

tgz 파일을 zip 파일로 변환하는 과정에서 생기는 비용때문인데, 

내가 글을 작성하는 2022-03-02 기준으로는 위와 같이 타 Yarn 친구들보다 약간 높은 비용 수준으로 npm보다는 훨씬 낮은 코스트가 드는 것을 확인할 수 있다.

 

아마 주 비용인 tgz->zip 프로세스에서 그동안 많은 기술적 향상이 있지 않았나 싶다?!

 

 

cache와 lock 파일 생성 이후에는 pnpm보다 약간 높은 코스트로 굉장히 빠른 것을 확인할 수 있다.

 

 

https://www.cleancoder.dev/package-manager-history/

 

자바스크립트 패키지 매니저의 여정

자바스크립트 패키지 매니저가 어떻게 발전했는지 알아보자.

www.cleancoder.dev

이 글의 내용을 메인으로 가져옴.

 

나도 저렇게 글 쓰고 싶다.

 

https://p.datadoghq.eu/sb/d2wdprp9uki7gfks-c562c42f4dfd0ade4885690fa719c818?tpl_var_npm=%2A&tpl_var_pnpm=%2A&tpl_var_yarn-classic=%2A&tpl_var_yarn-modern=%2A&tpl_var_yarn-nm=no&tpl_var_yarn-pnpm=no&from_ts=1645624957406&to_ts=1646229757406&live=true 

 

Package Manager Benchmarks | Datadog

 

p.datadoghq.eu

 

패키지 매니저 밴치마크

'TIL' 카테고리의 다른 글

TIL 2022-03-06 Shell, protobuf, gRPC  (0) 2022.03.06
TIL 2022-03-03 Storybook  (0) 2022.03.04
TIL 2022-02-24 Jest  (0) 2022.02.24
TIL 2022-02-23 GraphQL  (0) 2022.02.23
TIL 2022-02-22 SCSS  (0) 2022.02.22