본문 바로가기
Frontend/Etc

npm VS yarn Vs pnpm Vs yarn berry 뭘 써야 해???

by 이의찬 2023. 7. 7.

1. Why?

삼성청년SW아카데미에서 첫 프로젝트인 공통 프로젝트를 시작했다.

 

본격적으로 개발을 하기 전에 우선 어떤 기술을 사용할지부터 결정해야 하는데, 팀원 중 Package Manager에 대한 지식이 있는 사람이 없기에 어떤 Package Manager를 사용할지 찾아보고 팀원들에게 공유하고자 한다.


1. Package Manager가 뭔데,, 어디 쓰는건데,,

1) 모듈? 패키지?

좌) 모듈 우) 패키지

  • 모듈 → js에서 require라는 node.js의 도구를 사용해서 가져올 수 있는 것
  • 패키지 → 그런 모듈을 모아놓은 것

2 ) Package Manager란?

  • Package Manager가 없다면?
    • 사용하고 싶은 Package를 직접 다운로드 받아서 설치해야함
      • 의존성 처리? 그건 알아서..
    • 만약 사용하던 라이브러리가 업데이트 된다면?
      • 알아서 릴리즈노트 비교해가면서 업데이트 + 직접 코드 다운로드 받아서 새로운 버전으로 교체,,
  • Package를 관리하기 위해서 등장한 게 Package Manager
    • 프로젝트에 필요한 외부 라이브러리, 모듈, 플러그인을 설치하고 관리하는 역할
    • 여러 버전의 동일한 패키지를 한 프로젝트에서 사용
    • 설치방식 통일
    • 패키지 관련 정보가 들어있는 메타 데이터 간소화
  • 주요 기능
    1. 패키지 설치
      • Package Manager를 사용해 프로젝트에 필요한 패키지 설치
    2. 의존성 관리
      • Package는 다른 Packge에 의존할 수 있음(Package를 동작시키기 위해 다른 Package가 필수적으로 필요)
      • Package Manager는 이러한 의존성을 자동으로 해결해 필요한 Package를 설치
    3. 버전 관리
      • Package Manager는 Package의 버전을 관리함
      • 특정 버전의 Package를 설치하고 업데이트 가능
      • 프로젝트가 정확한 버전의 Package를 사용하도록 보장할 수 있음
    4. 스크립트 실행
      • 프로젝트에 미리 정의된 스크립트 실행 기능 제공
      • 이를 통해 빌드, 테스트, 배포 등의 자동화된 작업 수행

3) Package관리 파일

  1. package.json
    • package 버전 관리 파일
    • CLI로 해당 프로젝트가 의존하고 있는 모든 package이름과 버전을 기록
      • 설치해야 하는 패키지 → dependencies
        개발용 패키지 → dependencies
      • 설치 커맨드(npm i/yarn i)입력 시 여기 기록된 모든 패키지가 registry로 부터 다운받아져 node_modules에 저장됨
      • package.json만 있으면 의존하는 모든 패키지를 설치할 수 있기에 node_modules를 .gitignore파일에 추가
    • Code
      • scripts : npm 명령어 저장, npm run [명령어]로 스크립트 실행
      • 설치는 npm install [패키지명]으로 설치, 설치 패키지와 프로젝트 명이 겹치면 안됨
      • —save 옵션은 dependencies에 추가하는 명령어, npm v5부터 기본으로 설정
  2. node_modules
    • package.json에 기록된 package들이 실제로 설치되는 폴더
  3. package-lock.json(yarn.lock)
    • package 잠금 파일
      • 개발자끼리 서로 다른 버전의 package가 설치되는 것을 막아줌
      • → 같은 개발환경을 구성해줌
      • 프로젝트에 package가 최초로 추가될 때의 버전 기준
      • package.json에서는 버전을 version range(범위)로 명시하기에 정확한 버전은 lock파일에서 정해짐

2. npm VS yarn

0) npx

  • 패키지를 임시로 설치해서 실행하는 용도 → 그래서 CRA에서 사용

1) npm

  • 원조 / node.js의 기본 Package Manager
  • 그러나 문제점 많(았었)음
    • 일관적이지 않은 패키지 버전
    • 고정되지 않은 설치 순서
    • 병렬화 X 순차적인 설치 → 다운로드 속도가 매우 느림
  • 생각 없이 쓰기엔 괜찮음

2) yarn(yarn classic, yarn v1)

  • meta(페이스북)에서 제공
  • npm의 단점 개선
    • 병렬화를 통한 설치 속도 개선
    • 자동화 된 lock파일 yarn.lock 생성(npm은 예전엔 안해줬음)
    • 의존성 트리 알고리즘 변경
    • 캐시 사용
      • .yarn/cache를 통해 이미 다운되어 있는 패키지에 대한 정보 저장 → 중복 다운 X
  • 현재는 유지 보수만,, 새 프로젝트에서는 사용 권장 X

3. node_modules의 문제점

  • 근본적으로 node_modules의 문제 ⇒ 즉 npm과 yarn classic 둘 다 가지는 문제점

1) 모듈 탐색 과정의 비효율

  • package를 찾기 위해 순차적으로 상위 디렉토리의 node_modules를 탐색
  • 상위 디렉토리의 node_modules에 package가 없다면 계~속 찾아야 함
  • 중간의 node_modules가 버전이 다른 의존성을 가지고 있어도 사용해버릴 수 있음

2) 비효율적 설치

So,, So heavy,,,

  • node_modules 디렉토리는 수백MB의 크기와 많은 I/O 작업을 필요로 함
  • 이런 복잡하고 깊은 구조로 인해 의존성이 잘 설치되어 있는지 검증하기 어려움
    • Yarn Classic과 npm은 기본적인 의존성 트리의 유효성까지만 검증하고 package의 내용은 확인하지 않음

3) 유령 의존성(Phantom Dependency)

  • node_modules의 중복 설치로 인한 문제를 개선하기 위해 npm과 yarn classic에서는 Hoisting(끌어올리기)을 사용

어떻게 지평좌표계로 고정하셨나요?

  • 좌측 트리에서 A(1.0)과 B(1.0)패키지는 두 번 설치되기에 더 많은 공간과 시간이 소모됨
  • npm과 yarn은 Hoisting으로 이러한 문제를 해결
  • 하지만 직접 의존하고 있지 않은 B(1,0) 라이브러리를 require() 할 수 있게 됨 ⇒ 유령 의존성
  • 유령 의존성으로 인해 package.json에 명시되지 않은 라이브러리가 사용 가능해지거나, 다른 의존성을 package.json에서 삭제했을 때 같이 삭제되기도 함 ⇒ 의존성 관리 시스템에 혼란!

4. pnpm VS yarn berry

 💡 node_modules의 단점을 개선한 Package Manager

1) pnpm

  • Virtual Store
    • 모든 패키지를 저장하는 전역 저장소(Virtual Store)에서 패키지를 공유
    • 중첩된 패키지는 설치 X ⇒ 전역 저장소에서 가져다 쓰기
      1. Ghost Dependency 해결(명시한 패키지만 사용)
      2. 불필요한 I/O 과정을 없애 빠르고 효율적
      3. 패키지 중복 설치를 하지 않음으로써 사용 용량이 적음
       

  • npm프로젝트에 설치하면 즉시 사용 가능하며, 사용법도 거의 비슷

2) yarn berry(yarn v2)

yarn berry는 크게 두 가지 방식으로 package들을 관리한다.

  • Plug’n’Play(PnP)
    • 인터페이스 링커 (Interface Linker)
      1. node_modules 대신, 패키지들에 대한 정보를 zip으로 압축해 .yarn/cache 폴더에 저장
      2. 이를 찾기 위한 정보는 .pnp.cjs 파일에 생성 후 의존성 트리 정보를 단일 파일에 저장
      3. 설치 시간 및 용량 감소
      4. 의존성을 구성하는 파일의 수가 적음 ⇒ 변경 사항 감지 및 삭제 작업 속도 향상
  • Zero install
    • PnP 덕분에 수 백MB크기의 node_modules 대신 커봤자 200MB 정도 크기의 의존성 폴더를 갖게 됨
    • github는 파일 당 최대 500MB, 저장소 당 1GB 미만 크기를 권장함
    • 의존성 폴더를 통째로 git에 업로드하는 것이 가능해짐
      1. git clone 이후에 별도의 install 없이 바로 사용 가능
      2. CI에서 의존성 설치하는 시간이 크게 줄어들어 배포 시간도 단축!

5. 그래서 뭘 쓰는게 좋을지?

  • npm
    • 단점이 많음(느린 속도, 무거운 node_modules, 유령 의존성 등등,,)
    • 하지만 지속적 업데이트로 예전보다는 쓸만함
    • node.js의 기본 package manager라 사용 유저도 많고 트러블 슈팅도 쉬움
  • yarn classic
    • 이미 업데이트가 멈췄고 유지 보수만 하는 상태, 새 프로젝트에서는 사용할 이유가 없음
  • pnpm
    • Virtual Store를 이용해서 node_modules에서 비롯되는 문제들을 극복함
    • npm과 사용법이 비슷하기에(의존성 관리 방법은 전혀 다르지만) 쉽게 사용 가능
    • 단 npm보다 사용자가 적어 트러블 슈팅이 어려움
  • yarn berry
    • pnp를 사용해서 큰 용량인 node_modules를 아예 사용하지 않음
    • 그 덕에 zero install 가능 및 git clone 이후 별도의 설치가 필요 없음 → 배포 속도는 가장 빠름!
    • 다른 package manager와 다른 pnp 방식을 사용하기에 자잘한 에러가 있을 수 있음
    • 다만 PnP방식은 커밋을 하면 .git/objects에 변경된 파일이 zlib으로 압축되어 기록되기에 커밋의 수가 늘어나면 git에 부하가 걸릴 수 있음

모노레포와 보안성 등 더 고려해야할 것이 많은데 이건 추후에 따로 글을 쓰는걸로,,


참조