피어가 해결되는 방법
pnpm의 가장 좋은 기능 중 하나는 한 프로젝트에서 패키지의 특정 버전이 항상 하나의 의존성 세트를 갖는다는 것입니다. 하지만 이 규칙에는 한 가지 예외가 있습니다 - peer dependencies가 있는 패키지입니다.
피어 의존성은 그들의 부모와 동일한 버전을 공유하기 때문에 의존성 그래프에서 더 높게 설치된 의존성으로부터 해결됩니다. 즉, foo@1.0.0에 두 개의 피어(bar@^1과 baz@^1)가 있는 경우, 같은 프로젝트에서 여러 다른 종속성 세트를 가질 수 있습니다.
- foo-parent-1
- bar@1.0.0
- baz@1.0.0
- foo@1.0.0
- foo-parent-2
- bar@1.0.0
- baz@1.1.0
- foo@1.0.0
위의 예시에서 foo@1.0.0은 foo-parent-1과 foo-parent-2를 위해 설치됩니다. 두 패키지 모두 bar와 baz도 가지고 있지만, 서로 다른 버전의 baz에 종속됩니다. 그 결과 foo@1.0.0은 두 가지 다른 종속성 세트를 갖게 됩니다: 하나는 baz@1.0.0, 다른 하나는 baz@1.1.0입니다. 이러한 사용 사례를 지원하기 위해 pnpm은 서로 다른 종속성 세트의 수만큼 foo@1.0.0을 하드 링크해야 합니다.
일반적으로 패키지에 피어 종속성이 없으면, 다음과 같이 해당 종속성의 심볼릭 링크 옆에 있는 node_modules 폴더에 하드 링크됩니다:
node_modules
└── .pnpm
├── foo@1.0.0
│ └── node_modules
│ ├── foo
│ ├── qux -> ../../qux@1.0.0/node_modules/qux
│ └── plugh -> ../../plugh@1.0.0/node_modules/plugh
├── qux@1.0.0
├── plugh@1.0.0
그러나 foo에 피어 종속성이 있으면 여러 종속성 세트가 있을 수 있으므로, 서로 다른 피어 종속성 해석마다 다른 세트를 생성합니다:
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
│ ├── qux -> ../../qux@1.0.0/node_modules/qux
│ └── plugh -> ../../plugh@1.0.0/node_modules/plugh
├── 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
│ ├── qux -> ../../qux@1.0.0/node_modules/qux
│ └── plugh -> ../../plugh@1.0.0/node_modules/plugh
├── bar@1.0.0
├── baz@1.0.0
├── baz@1.1.0
├── qux@1.0.0
├── plugh@1.0.0
We create symlinks either to the foo that is inside
foo@1.0.0_bar@1.0.0_baz@1.0.0 or to the one in
foo@1.0.0_bar@1.0.0_baz@1.1.0.
결과적으로 Node.js 모듈 resolver는 올바른 피어를 찾습니다.
패키지에 피어 종속성은 없지만 그래프의 상위에서 해석되는 피어를 가진 종속성이 있는 경우, 해당 전이적 패키지는 프로젝트에서 서로 다른 종속성 세트로 나타날 수 있습니다. 예를 들어, 단일 종속성 b@1.0.0을 가진 패키지 a@1.0.0이 있습니다. b@1.0.0에는 피어 종속성 c@^1이 있습니다. a@1.0.0은 b@1.0.0의 피어를 절대 해석하지 않으므로, b@1.0.0의 피어에도 종속하게 됩니다.
다음은 node_modules에서 해당 구조가 어떻게 보이는지 보여줍니다. 이 예시에서 a@1.0.0은 프로젝트의 node_modules에 두 번 나타나야 합니다 - 한 번은 c@1.0.0으로, 또 한 번은 c@1.1.0으로 해석됩니다.
node_modules
└── .pnpm
├── a@1.0.0_c@1.0.0
│ └── node_modules
│ ├── a
│ └── b -> ../../b@1.0.0_c@1.0.0/node_modules/b
├── a@1.0.0_c@1.1.0
│ └── node_modules
│ ├── a
│ └── b -> ../../b@1.0.0_c@1.1.0/node_modules/b
├── b@1.0.0_c@1.0.0
│ └── node_modules
│ ├── b
│ └── c -> ../../c@1.0.0/node_modules/c
├── b@1.0.0_c@1.1.0
│ └── node_modules
│ ├── b
│ └── c -> ../../c@1.1.0/node_modules/c
├── c@1.0.0
├── c@1.1.0