⚽️ 목표
pnpm쟝... 내가.. 좀더 알아보게 허락해주겠어?
•
결론이 존재하지 않는 게시글입니다. 그냥 정리하면서 공부하면 더 잘되서 작성한 게시글 입니다.
TL;DR
symlink, hardlink를 이용하여 효율적인 디스크 공간 관리 및 속도를 중요시 하는 패키지 관리자 - 제일 합리적여
•
결국 돌고돌아(npm -> yarn -> yarn berry) pnpm으로 정착
•
추가된 pnpm 사용 이유 -> 마이너 감성 완.전.충.족.앗.흥.
1. pnpm 이해에 필요한 기본지식
content-addressable store(CAS)
•
이름이 너무기니까 이하 CAS로 통일
pnpm store path # ~/pnpm/store/v3 - pnpm 설치 방법마다 다름
Bash
복사
•
간단히 설명하면 패키지 파일 중앙 저장 관리소 이다. 복잡하게 생각하지말자. → 중앙이라는 키워드가 제일 중요
•
node_modules의 무거운 패키지 지옥을 해결하는 방법 중 하나.
•
npm, yarn의 경우
◦
예시) 리액트 18.0.2버전이 10개의 프로젝트에서 사용하고 있다. → npm이나 yarn의 경우 각 프로젝트마다 react 18.0.2가 프로젝트 마다 따로따로 설치되어 있다. 한마디로 같은 파일들의 10개 복사본이 각각 다른 위치에 파일을 보관하고 있음.
◦
여기서 문제점은 똑같은 리소스의 의미없는 저장용량 사용 + 설치 시 때 마다 파일 새로 네트워크에서 다운
▪
문제점 중 하나인 “설치 시 때 마다 파일 새로 네트워크에서 다운”은 최신 버전 패키지 매니저들에서 대부분 “캐싱”을 이용하여 네트워크 요청이 아닌 캐싱된 파일 복사로 진행되어 어느정도 해결된다. 그러나 파일 I/O로 인한 리소스 낭비는 완벽해결을 하지 못한 상태.
▪
“파일 I/O로 인한 리소스낭비..? 야.. 이건 좀 억지아니냐? 그게 얼마나 오래걸리는 작업이라고..” 할 수 있지만 일단 pnpm에 비교했을때 차이가 존재하는건 사실이기 때문에 짚고 넘어가야할 사실이다.
•
pnpm
◦
pnpm의 CAS에 실제 파일들이 저장되고 프로젝트에서 사용하고자 할때는 CAS에 저장된 파일들을 hardlink해 사용하기 때문에 설치 속도(네트워크 요청, file io가 없기 때문) 및 디스크 저장공간의 효율적인 관리가 가능하다.
◦
쉽게 풀어서 말하자면 “이미 존재하는 파일을 왜 다시받아? 같은 파일인데 그냥 링크해주면 되는거 아냐?”
inode
index-node의 줄임말로 파일에 대한 정보(해당 파일에 대한 소유권, 권한, 타임스탬프, 디스크 내 위치)를 가지고 있는 데이터 구조
ls -i # 138232 node_modules
Bash
복사
•
파일 시스템에 주민등록번호 -> 파일 시스템 내에 파일, 디렉터리들은 고유한 inode 값을 가지고 있다.
•
symlink(softlink 라고도 부름, 이하 symlink로 통일)로 연결된 파일은 같은 파일을 바라보고 있다 해도 서로 다른 inode를 가지고 있음
hardlink
•
다른 파일의 inode를 직접 참조하는 파일
•
A(원본) 파일이 삭제되더라도 A를 hardlink한 B 파일은 여전히 존재 및 참조 가능
•
보조기억장치에 저장된 파일 접근 시 inode를 활용하여 직접 접근하므로 symlink보다 성능이 비교적 좋음
•
디렉터리는 hardlink 불가능하다.
•
파일들이 하드링크된 파일은 용량을 추가로 갖지 않고 원본파일 하나만 존재한다.
symlink
•
윈도우의 바로가기와 비슷한 형태로 참조하는 파일
•
hardlink 처럼 파일을 직접 참조하지 않고, 참조하는 원본파일의 파일의 path를 갖고 있다. → 파일 참조 시 원본 파일을 경유하므로 hardlink에 비해 비교적 속도가 느리다.
•
A(원본) 파일이 삭제되되면 A를 symlink한 B파일은 참조 불가
•
디렉터리 symlink 가능
2. 들어가기 전 - npm의 node_modules 구조
•
npm이 가지고 있는 문제점을 알아야 “구지비 지금 잘 쓰고있는” npm에서 pnpm으로 넘어가지 않겠니?
유령 의존성
# npm의 패키지 설치 방식을 확인을 위한 테스트 프로젝트 초기화
mkdir npm1
npm init -y
npm install react
Bash
복사
•
node_modules 확인 시 호이스팅 된 패키지들을 확인 할 수 있다. → 나는 리액트만 설치했는데 직접 설치하지 않은 jstokens와 loose-envify 라이브러리들이 최상단에 존재한다. 이게 바로 유령 의존성.
cd node_modules
ls -a # .package-lock.json, react, js-tokens ,.bin, loose-envify
Bash
복사
◦
js-tokens, loose-envify 패키지가 npm의 shameful 한(pnpm 설정에선 shameful이라면서 뜯어 말리기 까지하는 결과물) 호이스팅의 결과물
.bin 디렉터리
•
사용자의 컴퓨터 아키텍쳐에 따라 미리 컴파일된 바이너리 또는 실행가능한 파일이 존재하는 디렉터리 → 해당 프로젝트 실행 시 필요한 실행파일들이 존재한다.
3. pnpm의 node_modules 구조
mkdir pnpm1
pnpm init
pnpm install react
cd node_modules
ls -a # react, .modules.yaml, pnpm
Bash
복사
•
실제로 사용자가 설치한 react 패키지만 (symlink, .pnpm 디렉터리에 존재하는 패키지) 최상단에 존재한다. 이로인해… 호이트스팅이 없고..
•
사용자가 설치한 패키지만 존재함 -> 유령 의존성이 해결된다.
•
.pnpm/react@18.2.0/node_modules/react의 symlink - 아직 이해 어려우니 일단 알고만 있도록! 아래에 추가설명
node_modules tree
node_modules의 tree 스크린샷
•
위에 설명했듯이 node_modules의 최상단에는 사용자가 설치한 라이브러리 만 존재한다.
•
최상단에 존재하는 라이브러리들은 .pnpm 디렉터리에 존재하는 파일들에 대한 softlink이다. 쉽게 접근 할 수 있도록 만든 바로가기와 같이 생각하자.
◦
“왜 하드링크 안해요? 그게 더 빠르다면서요” → 디렉터리는 하드링크 못한다고…!
•
.pnpm에 존재하는 파일들이 바로 CAS로 직접 연결된, hardlink된 파일들이다.
•
물론 이해가 어려울 것이다. 정작 나또한 해당 포스팅을 작성하며 “아.. 잠시만.. 그래서 뭐..?”를 외쳤으니.. → react 라이브러리를 이용한 예시를 들겠다.
graph TB A("node_modules/react@18.2.0") -.symlink.-> B("node_modules/.pnpm/react@18.2.0") ==hardlink===> storage[(CAS)]
Mermaid
복사
1.
node_modules의 최상단에 존재하는 react@18.2.0 라이브러리 디렉터리 → 해당 디렉터리는 .pnpm에 존재하는 파일에대한 symlink. 즉, 바로가기일 뿐 이다.
2.
.pnpm/react@18.2.0에 존재하는 파일들은 CAS에 존재하는 파일들에 대한 hardlink다.
4. .pnpm과 CAS를 실제로 연결시켜보기
•
pnpm1이라는 리액트 프로젝트에 node_modules/.pnpm/react@18.2.0의 inode를 확인하고 해당 파일이 실제 CAS에 존재하는지 확인해보자.
•
직접 확인해야 “아 이렇구나” 하고 넘어가는 성격이라 해본 것 뿐이다. 굳이 직접 따라하지 않아도 된다.
1. .pnpm 디렉터리에 존재하는 파일 확인하기
# .pnpm에 inode 확인
pwd # ~/pnpm1/node_modules/.pnpm
cd react@18.2.0/node_modules/react
Bash
복사
•
node_modules 최상단에 존재하는 파일들은 전부 CAS에 softlink 되어있으니 .pnpm 디렉터리로 바로 이동하여 react@18.2.0에 node_module/react로 이동한다.
2. 해당 파일의 inode 확인하기
ls -ali index.js # 4303682 -rw-r--r-- 35 khannewayne staff 190 Aug 18 22:30 index.js
Bash
복사
•
hardlink는 모두가 알다시피 파일만 링크가능하다. 임의의 파일의 inode를 확인한다.
3. CAS 위치 확인하기
# CAS위치 확인
pnpm store path # ~/pnpm/store/v3 - pnpm 설치 방법마다 다름
cd ~/pnpm/store/v3/files # CAS에 실제 패키지 파일들이 설치된 위치로 이동
Bash
복사
•
inode를 확인했으니 CAS의 주소를 확인하고 해당 주소로 이동하여 패키지를 이루는 파일들이 저장된 디렉터리로 이동한다.
4. CAS에서 inode 검색하기
node_modules/.pnpm/react@18.2.0/node_modules/index.js는 ~/pnpm/store/v3/files/25에 난수화된 이름으로 저장되어 있다.
find . -inum 4303682 # ./25/412e88974b83582fa47ec907cb4d2a30b9027a19215609...
Bash
복사
•
find 명령어를 이용해 inode를 기반으로 파일을 검색한다. - HIT!
◦
요기 잉네!
◦
다른 프로젝트에 똑같은 react@18.2.0을 설치해도 똑같은 inode를 가지고 있는 파일들이 설치된다! → 여기서 이해가 안됐다면 글 다시 읽어보자!
•
.pnpm에 존재하는 모든 파일들은 CAS에서 중앙 관리된다.
◦
프로젝트가 늘어나면 늘어날수록 용량적으로 더 효율 적인 관리가 가능하며 설치 속도는 덤! → 파일 I/O가 없잖아오!