Yarn vs. Pnpm 모노레포 간단 비교

실무에서 사용해보고 느낀 점

·

4 min read

실무 프로젝트에서 Yarn classic/berry workspace, Pnpm workspace를 사용해봤고, 개인적으로 느낀 각각의 장단점을 가볍게 적어본다. 수치적으로 정확히 비교하는 글은 아니라는 거~

  • 사실 구글 서치에서 내 블로그에 들어오는 검색어 1순위가 yarn berry monorepo 이기도 해서, 한번더 우려먹어보려는 거~

결론부터 말하면, 지금은 왠만하면 pnpm 을 사용해서 프로젝트를 구성하고 기존 yarn으로 되어있던 모노레포 프로젝트도 pnpm으로 이전하려고 하고 있다

의존성 설치 속도

  • 체감상 pnpm, yarn berry 둘다 비슷한 듯 하고, 둘다 빠르다

  • yarn berry는 순정 PnP 모드만 사용했을 때 .yarn/cache 디렉토리에 의존성들을 .zip 파일 형태로 저장한다.

      • 뇌피셜인데, 우선 zip 파일로 어느정도 압축이 되어있기 때문에 다운로드 용량 자체가 적어서 다운로드 시간 자체가 좀더 줄어들것 같고,

      • npm/yarn classic 처럼 npm 레지스트리에 있는 패키지 내부 파일들을 하나하나 다운 받는게 아니라 zip 파일 하나로 합쳐서 가져오기 때문에 http 요청-커넥션 프로세스도 줄어들기 때문에 좀더 빠르지 않을까 싶다

      • zero-install 설정을 하게 되면, (거창해보이지만 사실 git에 .yarn 디렉토리 저장해버리는 거) CI 환경에서 yarn install을 안해도 되기 때문에(!) 짧게는 1분에서 많게는 몇분에 달하는 설치 시간을 아낄 수 있다.

      • git으로 의존성 변경을 확인할 수도 있기 때문에, 나도 모르게 의존성이 버전업 되서 빌드 깨지는 걸 미리 막을수 있고, 여러 사람이 참여하는 프로젝트에서 버전이 꼬이는 문제도 방지할 수 있다.

  • yarn classic은, npm => yarn으로 갈아타기 했을 때는 뭔가 좀 빠른듯 하고 CLI에 이모지도 있고 해서 뭔가 힙해보이는 느낌도 있어서 그런지 느리다는 느낌은 없었는데, pnpm, yarn berry를 쓰다가 yarn classic을 쓰면 아직도 설치하고 있네하는 생각이 든다

호환성

  • yarn classic, pnpm을 쓰면서는 호환성 문제가 발생한 적은 없다

  • yarn berry는 내가 마지막으로 썼던 작년 중반 정도까지 호환성 문제가 있어서, 설치에 실패하거나 vscode에서 패키지를 인식 못해서 ts 에러가 나는 경우가 많았다. 아직도 일부 라이브러리들은 호환성 문제가 있는 걸로 알고 있다.

    • 호환성 문제를 해결하려면 할 수도 있는데, 그 중 하나는 이전 블로그 (https://hashnode.com/post/ckyhgtckf08vw35s14ppr0fz3) 에서 썼던 거처럼 설정 파일 .yarnrc.yml 에서 nodeLinker 를 설정해주는 방법이 있고,

      • 근데 이걸 하게 되면 의존성 설치하는게 두배가 된다. 이거는 아래 '디스크 사이즈'에서 알아보자
    • 아니면 .yarnrc.yml packageExtensions를 활용해서 라이브러리 마다 하나하나 이건 이거고 저건 저거다 설정해주는 방법이 있다. 근데 이걸 해주는게 패키지 매니저의 역할인데, 이걸 못해서 사용자가 직접 해준다는게.. 근본적으로 틀려먹은거 아닌가 모르겠음

  • 모노레포 툴인 turborepoyarn berry와 호환이 안된다. 어차피 모노레포를 deep하게 쓰는게 아니라면 yarn workspaces 그자체도 뭐 나쁘진 않은데, turborepo의 캐싱 기능이 필요한 경우에는 좀 많이 아쉽다

디스크 사이즈

  • 사실 node_modules.yarn/cache, .pnpm-store 디렉토리 사이즈를 정확하게 비교분석 해본 적은 없다. 그런거 재고 있을 시간도 없고.. 다만 배포할 때 도커빌드하고서 du 로 대충 어느정도 사이즈가 되는지 확인은 해보는 편인데, 세 패키지 매니저 모두 크게 차이는 없다

  • 다만 위 호환성 문제에서 yarn berry를 사용할 때 패키지 인식 문제 때문에 nodeLinker를 설정해서 node_modules 폴더를 사용하게 할 수가 있다. 그러면 zip파일로 설치한걸 node_modules에 한번 더 풀어서 zip파일로 인식이 안되면 node_modules에 있는걸 찾아서 사용하는 식이다.

  • 그러면 동일한 걸 하나는 .yarn/cache 안에서 zip파일로 갖고, 하나는 node_modules 안에서 압축해제 한걸로 갖고 있게 되는 셈이된다. 위 스크린샷에서 node_modules 폴더 사이즈가 무려 825메가가 나오는데, yarn berry nodeLinker를 하게 되면 의존성만 1.6기가를 사용하게 되는 거다

  • pnpmyarn berry와 유사하게 PnP 모드를 사용하기 때문에 node_modules 외에 .pnpm-store에 자체적으로 패키지들을 압축/변형한 걸 사용한다.

  • pnpm install을 할 때 우선 .pnpm-store에 압축된 파일들을 다운로드하고, 여기 있는 걸 node_modules에 풀어놓는 것 같다. 따라서 npm/yarn classic 보다는 디스크 용량을 좀더 차지할 수 있다

초기설정

  • npm은 Node.js를 설치하면, 왠만하면 자동으로 설치되는 거라 당연히 처음에 뭔가 해줄게 거의 없다

  • yarn classicnpm i -g yarn 아니면 corepack enable && corepack prepare yarn@latest --activate 정도 yarn 자체를 설치하는 거만 하면 바로 사용할 수 있다

  • yarn berryyarn set version berryyarn berry 사용 설정을 해주고, 에디터에 맞는 sdk를 설치하고, 플러그인들을 설치해야 한다

    • zero-install 같은 기능을 사용하려면 .gitignore에 어떤 디렉토리를 넣을 건지도 상황에 따라 고려해야 한다

    • pnp, zero-install 을 잘 쓰면 잘 쓸 수 있을 거고, 초기 설정들을 boilerplate로 만들어서 사용할 수도 있을 수 있겠지만, 아무튼 초기 설정하는데 손이 많이 간다. 귀찮다

  • pnpm 은 모노레포를 사용한다면 pnpm-workspace.yml 파일을 추가해서 패키지 경로들을 지정해준다

CLI 편의성

  • pnpm은 npm/yarn classic을 써봤다면 거의 바로 사용할 수 있다.

    • 의존성 설치를 할 때 npm 은 install을 사용하고, yarn은 add를 사용하는데, pnpm은 둘다 쓸수 있다. 기분 내키는대로 하면 된다

    • 모노레포에서 특정 패키지에만 해당하는 명령어를 사용할 때는 pnpm --filter='..' 를 사용하면 되는데, 내부 패키지의 패키지명을 다 쓸 필요가 없어서 편하다. 예를 들어 내부 패키지명이 @my-monorepo/app-a 라면 pnpm --filter=app-a run 어쩌구 로 실행하면 된다

  • yarn은 classic/berry 둘다 workspaces에서 특정 패키지만 명령어를 사용할 때 해당 패키지명을 모두 써줘야 한다. 예를 들어 내부 패키지명이 @my-monorepo/app-a 라면 yarn workspace "@my-monorepo/app-a" run 어쩌구로 실행한다