빠르고 효율적이며 안전한 패키지 매니저 - pnpm

iskkiri2024년 11월 05일
package manager
pnpm
workspace
monorepo
빠르고 효율적이며 안전한 패키지 매니저 - pnpm

JavaScript 생태계에서 널리 사용되는 패키지 매니저로 npmyarn이 있지만, 이들 모두가 해결하지 못한 성능, 디스크 공간 사용, 의존성 관리의 문제들이 존재합니다. 오늘 소개할 pnpm은 이러한 문제들을 해결하고, 더 빠르고 효율적이며 안전한 패키지 관리 경험을 제공합니다. pnpm의 핵심 장점을 4가지 주제로 정리해 보았습니다.

 

이번 글에서 언급하는 yarn은 yarn classic(v1)을 의미합니다. 

yarn berry의 경우 Plug’n’Play(PnP) 기능을 통해 phantom dependency 문제를 해결할 수 있습니다.

 

1. Fast - npm보다 최대 2배 빠른 속도

 

 

pnpm은 패키지 설치 속도가 npm에 비해 최대 2배 이상 빠릅니다. 이는 pnpm의 전역 콘텐츠 주소 저장소(content-addressable storage)와 하드 링크(hard link) 방식을 사용하여, 설치 중복을 줄이고 디스크 입출력을 최소화하기 때문입니다.

 

예를 들어, 여러 프로젝트에서 동일한 패키지가 필요할 때, pnpm은 해당 패키지를 단 한 번만 다운로드한 후 전역 스토어에 저장합니다. 이후 각 프로젝트의 node_modules에는 실제 파일을 복사하는 대신 하드 링크를 생성해 디스크 공간을 절약하면서도 빠르게 설치할 수 있습니다.

 

특히, 대규모 모노레포(monorepo) 환경에서 pnpm의 성능 차이가 극명하게 드러납니다. 중복 설치가 많은 프로젝트에서 pnpm은 훨씬 더 빠르게 설치 및 업데이트 작업을 수행합니다.

 

2. Efficient - 효율적인 디스크 공간 사용

 

npm과 yarn은 패키지를 각 프로젝트의 node_modules 폴더에 복제하여 디스크 공간을 많이 차지하지만, pnpm은 하드 링크와 심볼릭 링크를 사용하여 전역 스토어에서 패키지 파일을 공유합니다. 프로젝트가 여러 개라도 중복된 패키지 파일을 별도로 저장하지 않기 때문에, 디스크 사용량을 크게 줄일 수 있습니다.

 

예를 들어, 1MB 크기의 foo 패키지를 여러 프로젝트에서 사용할 경우, pnpm은 전역 스토어에 단 한 번만 foo를 저장하고 각 프로젝트에 하드 링크를 생성합니다. 이를 통해 실제로는 하나의 파일만 참조하여 디스크 공간을 효율적으로 절약합니다.

 

pnpm의 효율적인 디스크 사용 방식은 특히 디스크 용량이 제한적인 환경에서 큰 장점이 됩니다. 여러 프로젝트를 한꺼번에 관리할 때도, pnpm은 디스크 사용을 최소화합니다.

 

3. Supports Monorepos - 모노레포에 최적화된 워크스페이스 기능

 

모노레포(monorepo)는 하나의 저장소에서 여러 프로젝트를 관리하는 방법으로, 프로젝트 간 의존성을 쉽게 관리할 수 있어 대규모 개발팀에서 자주 사용하는 방식입니다. pnpm은 모노레포 환경에서 워크스페이스(workspace) 기능을 통해 패키지 간 의존성을 쉽게 연결하고 관리할 수 있도록 지원합니다.

 

pnpm 워크스페이스 설정 방법

 

  1. pnpm-workspace.yaml 파일 생성

모노레포 루트에 pnpm-workspace.yaml 파일을 생성하여 관리할 패키지 경로를 설정합니다.

 

packages:
  - "packages/*"  # 모든 패키지 경로 설정

 

이를 통해 packages 폴더 아래 모든 프로젝트가 워크스페이스의 일부로 관리됩니다.

 

  1. Workspace Protocol

pnpmworkspace: 프로토콜을 통해 로컬 패키지 간의 의존성을 연결할 수 있습니다. 예를 들어, bar 패키지가 foo를 의존할 때 다음과 같이 선언합니다.

 

{
  "dependencies": {
    "foo": "workspace:*"
  }
}

 

이를 통해 pnpm은 패키지를 전역 저장소에서 가져오는 대신, 로컬 워크스페이스에서 직접 의존성을 해결합니다. 이 방식은 패키지의 최신 버전을 자동으로 연결해주기 때문에, 빠르고 일관된 개발 환경을 제공합니다.

 

  1. 패키지 재사용성과 코드 일관성 유지

모노레포에서는 동일한 패키지를 여러 프로젝트에서 재사용할 수 있습니다. pnpm의 워크스페이스 기능은 중복 설치를 피하고, 하나의 저장소에서 의존성을 관리하여 프로젝트 간의 코드 일관성을 유지하고 변경 사항을 쉽게 반영할 수 있도록 돕습니다.

 

4. Strict - 명확한 의존성 관리로 안전한 패키지 사용

 

pnpm의 고유한 특징 중 하나는 명확한 의존성 관리입니다. 기존 npm과 yarn classic은 node_modules를 평평하게(flat) 구성하여, phantom dependency 문제가 발생하기 쉽습니다.

 

Phantom Dependency란?

 

Phantom Dependencypackage.json에 명시되지 않은 의존성을 프로젝트가 무심코 사용하는 문제를 말합니다. 예를 들어, 패키지 A가 B를, B가 C를 의존할 때, C가 node_modules의 루트에 설치되기 때문에 A가 C를 명시적으로 요구하지 않아도 접근이 가능합니다. 이는 배포 시 의존성 누락 및 예기치 않은 오류를 유발할 수 있습니다.

 

pnpm은 중첩된(node_modules의 비평평한) 구조를 사용하여 이 문제를 방지합니다. pnpm에서 의존성을 명확히 선언하지 않으면 접근할 수 없기 때문에 phantom dependency 문제를 사전에 차단해 안전성을 높입니다. 예를 들어, pnpm을 통해 설치한 경우 node_modules에 패키지가 중첩 구조로 설치되므로, 프로젝트에서 선언되지 않은 의존성은 접근이 불가능합니다. 이렇게 pnpm은 명확한 의존성 관리를 통해 신뢰성 높은 개발 환경을 제공합니다.

 

5. CI/CD 환경에서 pnpm 사용하기 

 

pnpm은 GitHub Actions 같은 CI/CD 환경에서도 빠르고 효율적으로 동작합니다. Corepack을 활용하면 CI/CD 환경에서 pnpm을 쉽게 설정하고 사용 가능합니다.

 

name: Test

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - run: corepack enable
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - name: Install dependencies
        run: pnpm install
      - name: Test
        run: pnpm vitest --coverage

 

위 예제처럼, CI/CD 환경에서도 빠르게 설치와 테스트를 수행하여 개발 워크플로우 속도를 높일 수 있습니다.

빠르고 효율적이며 안전한 패키지 매니저 - pnpm