npm과 yarn berry v2

김태완·2023년 11월 20일
0

프론트엔드

목록 보기
30/30

기존 npm의 문제점

npm은 범용적으로 많이 사용되나 비효율적인 측면이 많다.

비효율적인 의존성 탐색

npm은 파일 시스템을 사용해 의존성을 관리하는데, 예를들어 Users/test/dev/components라는 폴더에서 require로 lodash라는 패키지를 불러오는 상황을 가정할때
require.resolve.paths()를 사용해 검색하는데 npm은 해당 패키지를 찾기위해 아래처럼 계속 상위 디렉토리를 탐색한다.
일반적으로 이런 I/O 호출은 느리게 진행된다.

$ node
Welcome to Node.js v12.16.3.
Type ".help" for more information.
> require.resolve.paths('lodash')
[
  '/Users/test/dev/components/repl/node_modules',
  '/Users/test/dev/components/node_modules',
  '/Users/test/node_modules',
  '/Users/node_modules',
  '/node_modules'
  
  ...

]

비효율적인 설치

node_modules는 수백메가바이트 수준의 매우 큰 공간을 차지한다.
이로인해 복잡도는 올라가고 검증이 어렵다. 수백개의 패키지가 서로 의존한다면 node_modules의 디렉토리 구조는 매우 깊어질것이다.

유령 의존성 (Phantom Dependency)

npm 및 yarn v1은 중복설치를 막기위해 Hoisting기법을 사용한다.

아래 이미지를 보면 A(1.0)B(1.0)이 중복되기 때문에 Hoisting 하여 디스크 낭비를 방지한다.


하지만 이런 과정에서 기존에는 require할수 없었던 B(1.0)을 불러올수있게 된다.
따라서 package.json에 명시되지않은 B(1.0)을 package-1에서 가져올수있게되는 현상이 발생하고 이를 유령의존성이라 부른다.

Plug 'n' Play (PnP)

yarn berry는 위 문제를 Plug 'n' Play 전략으로 해결한다.

pnp의 배경

yarn v1은 package.json 기반으로 의존 트리를 생성하고 디스크에 node_modules 구조를 만든다.
따라서 의존성 관리가 불완전한 파일시스템이 아닌 보다 안전한 의존성 관리를 위해 시작됐다.

Pnp 켜기

npm최신 버전에서 yarn을 내려받고 버전을 berry로 설정하면 된다,

npm i -g yarn
cd ../path/to/some-package
yarn set version berry

yarn berry는 하위호환을 위해 패키지 단위로만 도입 할 수 있다

Pnp 동작방법

yarn berry는 node_modules를 생성하지않는 대신, .yarn/cache폴더에 의존성 정보가 저장되고, .pnp.cjs파일에 의존성을 찾을수있는 정보가 기록된다.
이는 디스크 I/O작업이 없이 빠르게 동작한다.

예를들어 react패키지는 .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"]
    ],
  }]
]],

yarn은 node가 제공하는 require문을 덮어씀으로 node명령어 대신 yarn node명령어를 사용해야 한다

$ yarn node

Zip FileSystem

.yarn/cache폴더 내부에 각 의존성들은 zip파일로 관리된다.
이로인해

  • node_modules 구조 생성이 필요없어져 설치가 빨라진다
  • 각 패키지는 버전마다 하나의 zip을 가지기 떄문에 중복설치가 되지않고 용량을 크게 아낄수있다
  • 의존 구성 파일의 수가 적어서 변경감지, 의존삭제 작업이 빠르다

PnP의 장점

의존성 검색

  • 의존성 검색시 node_modules 폴더를 순회하지 않아도된다.
  • .pnp.cjs파일이 제공하는 자료구조를 이용해 바로 의존성 위치를 찾기때문.

재현 가능성

  • 패키지 모든 의존성은 .pnp.cjs파일로 관리되기때문에 외부환경에 영향을 받지않는다.
  • 이로인해 다양한 환경에서 require과 import문의 동일한 동작을 보장받을수있다

의존성 설치

  • node_modules 폴더 생성이 필요없음
  • zero install
  • 이로인해 CI에 소비되는 시간을 단축가능

엄격한 의존성 관리

  • npm처럼 의존성을 hoisting하지않는다. 이로인해 각 패키지들은 자신이 package.json에 기술하는 의존성에만 접근함.
  • 유령 의존성 현상을 막을수있다

의존성 검증

  • 기존 node_modules에선 올바른 의존성 설치가 되지못해 폴더를 지우고 다시 설치해야하는 경우가 발생했다(검증이 어려웠다)
  • yarn pnp 에선 zip파일로 관리하기때문에 의존성을 찾거나, 변경을 감지하기 쉬워짐. 이로인해 의존성 검증이 쉬워졌다.

Git으로 의존성 관리(Zero install)

node_modules에 비해 zip파일로 관리하기 때문에 용량이 매우 적고 git 으로 관리가능함.
이로 인한 장점으로

  • CI에서 의존성 설치시간을 크게 줄일수있다
  • 새로 저장소를 복제하거나 브랜치를 바꾸어도 yarn install을 하지않아도 된다

요약하자면
npm은 비효율적인 탐색, 의존성 중복으로 인해 매우 무겁고 복잡하여 의존성관리 및 검증이 힘들다.
yarn berry는 zip아카이브와 .pnp.cjs로 관리하기 때문에 순회 과정이 필요없고 매우 가볍고 의존성 관리 및 검증이 쉽다.
따라서 CI에서 많은 시간을 줄일수있고 의존성도 더 엄격하게 관리가 가능하다!

참고

https://toss.tech/article/node-modules-and-yarn-berry
https://velog.io/@dev_jiminn/MonoRepo-with-Yarn-Berry

profile
프론트엔드개발

0개의 댓글