[ 살펴보기 ] Pnpm - Basics
![[ 살펴보기 ] Pnpm - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1727017225106/6c56a6bd-c173-4494-8465-3762045e6194.jpeg)
Pnpm을 통해 package를 설치하면 Pnpm은 global store에 해당 package를 설치하고 project 폴더의 node_modules에는 package대신 .pnpm 폴더를 생성하여 그곳에 global store에 설치된 package에 대한 hard link를 생성한다. 그리고 project의 node_modules에 각 package에 대한 symlink를 생성한다. ( symlink는 .pnpm에 생성된 hard link를 가리킨다 )
다른 project에서 특정 package를 설치할 때 해당 package가 global store에 존재하면 해당 package를 새로 설치하는 대신 project의 node_modules/.pnpm 파일에 global store에 존재하는 package에 대한 hard link를 생성하여 이미 설치된 package를 그대로 사용한다.
Pnpm은 이러한 방법을 통해 서로 다른 프로젝트에서 같은 package를 할 때 해당 package를 두 곳에서 다 설치하는 대신 이미 설치된 package를 다시 사용할 수 있게 함으로서 사용자의 disk space를 아껴준다.
Installation & Basic Cli
Corepack을 사용하면 pnpm을 바로 사용할 수 있게 해주므로. Corepack을 통해 pnpm을 사용하는 법을 살펴보자. Node 16.13 version 이상을 사용하고 있다면 corepack을 사용할 수 있다.
만일 다른 방법을 통해 pnpm 설치를 원한다면 documentation을 참고하자.
다음 명령어를 실행시켜 pnpm을 사용할 수 있는 상태로 만들어 준다.
corepack enable pnpm
그리고 project 폴더에서 다음 명령어를 실행하면 해당 project가 특정 pnpm version을 사용하도록 설정할 수 있다.
corepack use pnpm@latest
위의 명령어를 실행하면 project package.json에 packageManager property가 추가되고 packageManager property에 위의 명령어를 통해 설정한 pnpm version 정보가 추가된다.
Command Line Interface는 npm과 일부 다른 부분도 있지만 크게 다르진 않다.
npm install → pnpm install
npm install <package> → pnpm add <package>
npm run <command> → pnpm <command>
npm uninstall <package> → pnpm remove <package>
Pnpm Command Line Interface는 다른 포스트에서 보다 자세히 살펴보기로 하자.
Node_modules link 구조
PNPM documentation에서 사용하는 예제를 통해 node_modules에 link structure가 어떻게 형성되는지 살펴보자.
현재 project의 dependency가 다음과 같다고 가정해보자.
{
...
"dependencies": {
"foo": "1.0.0"
}
}
그리고 foo@1.0.0 package는 bar@1.0.0 package를 dependency로 가지고 있다고 가정한다. 즉, foo@1.0.0 package의 package.json은 아래와 같다.
{
...
"dependencies": {
"bar": "1.0.0"
}
}
pnpm가 위 dependency를 설치할 때 project node_modules/.pnpm에 아래와 같이 각 packages에 대한 hard link를 생성한다.
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
그런 다음 bar는 foo package의 dependency이므로 .pnpm/foo@1.0.0/node_modules에 bar package의 symlink가 추가된다. 이 때 추가된 bar symlink는 node_modules/.pnpm에 추가된 bar package hard link를 가리킨다.
node_modules
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar
그리고 project의 node_modules에 project direct dependency의 symlink가 추가된다. 위의 예제에서 project의 direct dependency는 foo@1.0.0이다.
node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ ├── bar -> <store>/bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
├── foo@1.0.0
│ └── node_modules
│ ├── foo -> <store>/foo
│ ├── bar -> ../../bar@1.0.0/node_modules/bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
└── qar@2.0.0
└── node_modules
└── qar -> <store>/qar
만약 같은 package지만 다른 version의 pacakge가 peerDependency로 있으면 link 구조는 어떻게 될까? project의 direct dependency가 다음과 같다고 가정해보자.
{
...
"dependencies": {
"foo-address":"1.0.0",
"foo-name":"1.0.0",
}
}
그리고 foo-address, foo-name 모두 foo@1.0.0을 dependency로 가지고 있고 foo package의 package.json은 다음과 같다고 가정해보자.
{
...
"peerDependencies": {
"baz":"^1",
"bar":"1.0.0",
},
}
위에서 foo package의 peerDependency에 정의된 baz package는 carrot version range를 허용한다. 만약 project 초기에는 foo-name package 없이 진행하다 시간이 지나 필요에 의해 foo-name package를 설치하는데 baz package의 새로운 minor version이 나와 있다면 아래와 같은 상황이 가능하다.
foo-address@1.0.0
- foo@1.0.0
- baz@1.0.0
- bar@1.0.0
foo-name@1.0.0
- foo@1.0.0
- baz@1.1.0
- bar@1.0.0
만약에 dependency graph가 위와 같은 상황일 때 pnpm은 대략 다음과 같이 project dependency에 대한 link를 구성한다.
node_modules
└── .pnpm
├── foo@1.0.0_bar@1.0.0+baz@1.0.0
│ └── node_modules
│ ├── foo
│ ├── bar -> ../../bar@1.0.0/node_modules/bar
│ ├── baz -> ../../baz@1.0.0/node_modules/baz
├── foo@1.0.0_bar@1.0.0+baz@1.1.0
│ └── node_modules
│ ├── foo
│ ├── bar -> ../../bar@1.0.0/node_modules/bar
│ ├── baz -> ../../baz@1.1.0/node_modules/baz
├── bar@1.0.0
├── baz@1.0.0
├── baz@1.1.0
즉, package는 같지만 다른 version의 peerDepency가 존재하는 상황일 때는 위의 예제와 같이 같은 package의 link가 실제 의존하는 peerDepency의 version에 맞게 여러개 생길 수 있다. 위의 예제에서는 foo에 대한 link가 두 개 생긴 것을 확인할 수 있다.
PeerDependency reposution에 대한 보다 자세한 정보는 documentation을 통해 확인할 수 있다. ( How peers are resolved )
![[ 살펴보기 ] RDB - Relationships](https://cdn.hashnode.com/res/hashnode/image/upload/v1739711556668/48dc9e84-a621-42aa-9c9f-5fc5c436f0ec.jpeg)
![[ 살펴보기 ] MySQL - Data types](https://cdn.hashnode.com/res/hashnode/image/upload/v1739593589113/530f8704-4d27-42c9-a451-bb5c63150b99.jpeg)
![[ 살펴보기 ] TypeORM - Transactions, Migration](https://cdn.hashnode.com/res/hashnode/image/upload/v1739106042581/980b8133-61d4-406a-a026-65be9c28eace.jpeg)
![[ 살펴보기 ] TypeORM - Relations](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666874402/b688bd0b-b6bb-4f43-87d8-c1b46b59f1b7.jpeg)
![[ 살펴보기 ] TypeORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666803591/bef5df17-7dc7-4123-ae55-004d5042df39.jpeg)