피어가 해결되는 방법
pnpm의 가장 좋은 기능 중 하나는 한 프로젝트에서 패키지의 특정 버전이 항상 하나의 의존성 세트를 갖는다는 것입니다. 하지만 이 규칙에는 한 가지 예외가 있습니다 - 피어 종속성이 있는 패키지입니다.
피어 의존성은 그들의 부모와 동일한 버전을 공유하기 때문에 의존성 그래프에서 더 높게 설치된 의존성으로부터 해결됩니다. 즉, 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
foo@1.0.0_bar@1.0.0+baz@1.0.0 안에 있는 foo 또는 foo@1.0.0_bar@1.0.0+baz@1.1.0 안에 있는 foo에 대한 심볼릭 링크를 만듭니다.
결과적으로 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