카테고리 없음

pnpm의 symlink, hardlink, hoisting 알아보기

jrpark91 2025. 4. 11. 16:14

공식문서 링크: https://pnpm.io/ko/symlinked-node-modules-structure

1. npm과 pnpm 차이

  • npm: 프로젝트마다 필요한 패키지를 실물로 복사한다 → 용량 크고 설치 느림
  • pnpm: 모든 패키지를 .pnpm 공용 스토어에 한 번만 넣고, 각 프로젝트에는 링크만 건다 → 용량 절약 + 설치 빠름

예시 상황

project라는 앱이 있고, 여기에 foo라는 라이브러리를 설치했는데 foo는 내부적으로 bar라는 라이브러리를 사용하는 상황입니다.

pnmp install foo@1.0.0 생기는 일

1. 실제 라이브러리 코드가 있는 파일이 하드링크를 활용하여 생성됩니다.

node_modules
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       └── bar -> <store>/bar
    │           ├── index.js
    │           └── package.json
    └── foo@1.0.0
        └── node_modules
            └── foo -> <store>/foo
                ├── index.js
                └── package.json

2. 노드 modules에서 링크로 .pnpm 내부를 바라봅니다.

node_modules/
├── foo → .pnpm/foo@1.0.0/node_modules/foo
└── .pnpm/
    ├── foo@1.0.0/
    │   └── node_modules/
    │       ├── foo → ../../../../store/foo
    │       └── bar → ../../bar@1.0.0/node_modules/bar
    └── bar@1.0.0/
        └── node_modules/
            └── bar → ../../../../store/bar
  • foo와 bar는 .pnpm 디렉토리 내에 실제 파일이 저장되며, 이는 하드 링크를 통해 전역 저장소에서 가져옵니다.
  • foo는 자신의 node_modules 내에 bar에 대한 심볼릭 링크를 생성하여 의존성을 관리합니다.
  • 최상위 node_modules에는 foo에 대한 심볼릭 링크만 존재하며, 이는 프로젝트의 직접적인 의존성을 나타냅니다.

 

2. 평탄화란?

pnpm이 하드링크를 통해 중복을 최소화 한다면, npm은 평탄화를 합니다.

npm의 평탄화 (hoisting)

project/
└─ node_modules/
   ├─ foo/              # 실제 파일(복사본)
   └─ bar/              # 실제 파일(복사본) ← 평탄화되어 루트로 올라옴
 
  • 원래 bar는 foo의 의존성이지만, 루트에 끌어올림
  • => require('bar') 같은 코드가 루트에서도 동작하게 하려고

 

3. 심링크와 하드링크

심링크

  • 파일의 "경로"를 가리키는 링크
  • 윈도우의 바로가기(lnk), macOS의 alias와 유사
  • 삭제 대상이 사라지면 깨진 링크가 됨 (dangling symlink)

하드링크

  • 파일의 실제 데이터(inode)를 가리키는 또 하나의 이름
  • 원본 파일과 동등한 파일처럼 동작
  • 원본 파일을 삭제해도 내용은 남아 있음 (다른 링크가 가리키고 있으면)
my-project/
├── node_modules/
│   ├── foo → .pnpm/foo@1.0.0/node_modules/foo     # 심링크
│   ├── .bin/                                       # 실행 파일 링크
│   └── .pnpm/
│       ├── foo@1.0.0/
│       │   └── node_modules/
│       │       ├── foo  → 하드 링크 → ~/.pnpm-store/v3/files/<hash>/foo
│       │       └── bar  → 하드 링크 → ~/.pnpm-store/v3/files/<hash>/bar
│       └── bar@1.0.0/
│           └── node_modules/
│               └── bar → 하드 링크 → ~/.pnpm-store/v3/files/<hash>/bar
├── package.json
└── pnpm-lock.yaml