카테고리 없음
pnpm의 symlink, hardlink, hoisting 알아보기
jrpark91
2025. 4. 11. 16:14
공식문서 링크: https://pnpm.io/ko/symlinked-node-modules-structure
1. npm과 pnpm 차이 비유
npm은 프로젝트마다 필요한 짐(패키지)을 전부 새로 복사해서 트럭에 실어줌.
→ 똑같은 짐도 프로젝트마다 다 따로 실어야 하니까 공간 많이 차지하고, 시간 오래 걸림.
pnpm은 모든 짐을 공용 창고에 한 번만 넣어두고, 각 프로젝트에는 링크만 걸어줌 (하드 링크라고 함).
→ 똑같은 짐을 여러 번 옮길 필요가 없어서 공간 절약되고 빠름.
예시 상황
project라는 앱이 있고, 여기에 foo라는 라이브러리를 설치했는데
foo는 내부적으로 bar라는 라이브러리를 사용
pnmp install foo@1.0.0 생기는 일 (foo는 bar를 의존성으로 가짐)
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. 평탄화란?
npm의 평탄화 (hoisting)
node_modules/
├── foo/
├── bar/ ← 평탄화: 의존성 bar가 루트에 올라옴
- 원래 bar는 foo의 의존성이지만, 루트에 끌어올림
- => require('bar') 같은 코드가 루트에서도 동작하게 하려고
pnpm은 평탄화 안 함 (기본값)
node_modules/
├── foo → .pnpm/foo@1.0.0/node_modules/foo
.pnpm/
└── foo@1.0.0/
└── node_modules/
├── foo/
└── bar/
- bar는 foo 내부에서만 접근 가능
- 루트에서 require('bar') 하면 못 찾음
3. 심링크와 하드링크
심링크
- 파일의 "경로"를 가리키는 링크
- 윈도우의 바로가기(lnk), macOS의 alias와 유사
- 삭제 대상이 사라지면 깨진 링크가 됨 (dangling symlink)
하드링크
- 파일의 실제 데이터(inode)를 가리키는 또 하나의 이름
- 원본 파일과 동등한 파일처럼 동작
- 원본 파일을 삭제해도 내용은 남아 있음 (다른 링크가 가리키고 있으면)
my-project/
├── node_modules/
│ ├── foo → ⤴ symlink → .pnpm/foo@1.0.0/node_modules/foo
│ ├── .pnpm/
│ │ ├── foo@1.0.0/
│ │ │ └── node_modules/
│ │ │ ├── foo → 하드 링크 → ~/.pnpm-store/foo
│ │ │ └── bar → 하드 링크 → ~/.pnpm-store/bar
│ │ └── bar@1.0.0/
│ │ └── node_modules/
│ │ └── bar → 하드 링크 → ~/.pnpm-store/bar
│ └── .bin/
│ └── foo → CLI 실행용 링크
├── package.json
├── pnpm-lock.yaml