Skip to content

패키지 매니저 비교

SeongYeon edited this page Nov 7, 2024 · 1 revision

패키지 매니저란?

  • 소프트웨어 패키지의 설치, 업데이트, 수정, 삭제를 자동화 하는 도구이다
  • 의존성 관리를 위해 자동화하여 개발 효율을 높인다
  • 패키지 버전 관리를 통해 일관성을 유지할 수 있다.
// 표준에서 요구하는 방식
import React from '/Users/raon0211/path/to/react/index.js';
// 실제로 우리가 사용하는 방식
import React from 'react';

버전 관리의 필요성

  • 같은 패키지도 여러 버전이 존재한다
// react의 경우
"react": "18.0.1"
"react": "18.3.1"
"react": "19.0.0-beta"
  • 정확한 버전 관리 정보를 제공하는 파일은 소스 코드 상위 package.json 에 명시한다
{
  "dependencies": {
    "react": "^18.2.0",    // 18.2.0 이상, 19.0.0 미만
    "lodash": "~4.17.21",  // 4.17.21 이상, 4.18.0 미만
    "axios": "1.4.0"       // 정확히 1.4.0 버전만
  }
}

버전 표기법

  • ^(캐럿): Major 버전 내에서 자동 업데이트.
    • ^18.2.0 → 18.2.0 ~ 18.9.9
  • ~(틸드): Minor 버전 내에서 자동 업데이트
    • ~18.2.0 → 18.2.0 ~ 18.2.9
  • 정확한 버전: 특정 버전만 사용
    • 1.4.0 정확히 1.4.0 버전

위와 같이 명시된 의존성을 바탕으로 패키지 매니저가 명시된 버전에 맞는 패키지를 다운로드 한다.

패키지 매니저 동작 단계

Resolution(의존성 해결 단계)

1. react@^18.0.0 분석
   ├── 18.0.0부터 19.0.0 미만 버전 검색
   ├── react의 의존성 확인
   │   ├── loose-envify@^1.1.0 필요
   │   └── loose-envify도 Resolution 과정 시작
   └── 최신 호환 버전 18.2.0 선택

2. lodash@^4.17.21 분석
   ├── 4.17.21부터 5.0.0 미만 버전 검색
   └── 의존성 없음, 4.17.21 선택

3. axios@^1.4.0 분석
   ├── 1.4.0부터 2.0.0 미만 버전 검색
   ├── axios의 의존성 확인
   │   ├── follow-redirects@^1.15.0
   │   ├── form-data@^4.0.0
   │   ├── proxy-from-env@^1.1.0
   │   └── 각각에 대해 Resolution 과정 반복
   └── 1.4.0 선택
  • 패키지 매니저는 Resolution 단계에서 package.json 파일이 명시된 버전 범위에 따라 정확한 버전을 결정한다.
  • 즉 위에서 설명한 버전 표기법 규칙에 따라 패키지 매니저는 저 범위를 만족하는 선에서 가능한 최신 버전을 사용한다.
  • 또한 설치된 라이브러리 간 의존성을 확인한다
    • 즉 의존성이 또 어떤 의존성을 가지는지 확인하는 작업이 필요하다
  • 위 과정의 결과물은 yarn.lock 이나 package-lock.json 에 저장한다.

Fetch(다운로드 단계)

1. 캐시 확인
   ├── .yarn/cache/ 디렉토리 검사
   └── 이미 있는 패키지는 다운로드 건너뛰기

2. 필요한 패키지 다운로드 (병렬 처리)
   ├── react-18.2.0.tgz
   ├── loose-envify-1.4.0.tgz
   ├── lodash-4.17.21.tgz
   ├── axios-1.4.0.tgz
   └── axios의 의존성 패키지들

3. 무결성 검사
   ├── 각 패키지의 SHA-512 해시 계산
   └── lock 파일의 integrity 값과 비교

4. 캐시 저장
   └── 다운로드된 패키지를 캐시에 저장
  • Resolution 단계에서 결정된 정확한 버전의 패키지들을 다운로드하는 과정이다.
  • 일반적으로, 99%는 npm 레지스트리에서 받아온다.

Link 단계(연결 단계)

  • 다운로드 된 패키지를 프로젝트에서 사용 가능하도록 연결하는 과정이다.
  • Link 단계는 npm, pnpm, PnP(Plog’n Play) 각각 다르게 동작한다

NPM/Yarn Classic

node_modules/
├── react/
├── lodash/
└── .bin
  • node_modules 기반의 Linker 는 package.json에서 명시하는 의존성을 그냥 node_modules 디렉토리 밑에다 하나하나씩 작성한다.

문제점

  • 패키지를 찾으려 할 때 node_modules 를 탐색하는 과정에서 파일을 여러번 읽어야 해서 속도가 느리다.
  • 또한 node_modules디렉토리 크기가 너무 커진다.

PNPM

node_modules/
.pnpm/
  • 위의 단점들을 해결하기 위해 pnpm이 등장
  • pnpm은 퍼포먼스가 향상된(performant) npm 으로 이해하면 된다

npm Linker 해결 방법

  • node_modules디렉토리를 그대로 사용하는 대신 보다 빠르고 용량을 최적화하는 방식을 사용한다
  • Hard link 방식을 활용한다
    • npm 처럼 단순 복붙하는 방식이 아닌 alias를 거는 방식이다.
    • 의존성이 디스크에 하나만 설치된다.
  • node_modules 디렉토리 크기도 매우 작다

Yarn

Yarn Berry(PnP Linker)

.pnp.cjs
.yarn/cache/
  • node_modules디렉토리에서 탈출하고 싶다는 생각으로 접근한 방식

  • PnP방식은 node_modules를 디렉토리로 관리하지 않고 Javascript 객체로 처리한다.

  • PnP 방식은 의존성을 찾는 방법을 JavaScript Map으로 관리한다.

    • .pnp.cjs 파일
      • 프로젝트의 루트에 .pnp.cjs 라는 파일을 생성합니다. 이 파일은 모든 패키지에 대한 metadata와 경로 정보를 담고 있습니다.
      • 각 패키지가 어디에 위치하는지를 매핑하기 위해 JavaScript Map구조를 사용합니다.
    • 패키지 찾기
      • .pnp.cjs 파일을 참조하여 필요한 패키지가 어디에 있는지 빠르게 찾습니다.
    • 캐시 디렉토리
      • .yarn/cache/ 디렉토리는 설치된 패키지들의 캐시를 보관합니다. 이 캐시를 PnP방식에서 필요할 때마다 빠르게 패키지를 가져오는 데 사용됩니다.
  • 패키지 설치를 위해 node_modules 디렉토리를 순회할 필요가 없어 속도 측에서 큰 장점이 있다.

PnP vs Zero-install

  • 우선 PnP와 Zero-install은 명확히 다른 개념이다

PnP

  • node_modules 없이 JavaScript Map 객체를 활용해 의존성을 엄격하고 빠르게 관리하는 접근 방식

Zero-install

  • PnP의 JavaScript Map 객체와 Fetch 된 의존성들까지 모두 Git에 넣어 버전을 관리하는 방식이다
  • Zero-install 방식은 레포지토리 사이즈가 커지고, Git 관리가 어려워진다는 단점이 존재하여 Zero-install 을 끄는 방향으로 가고 있다.

image

참고

https://toss.tech/article/lightning-talks-package-manager

💻 개발 일지

💻 공통

💻 FE

💻 BE

🙋‍♂️ 소개

📒 문서

☀️ 데일리 스크럼

🤝🏼 회의록

Clone this wiki locally