peer dependency는 어떠한 상황에서 사용할까?
지금까지 개발하면서 peer dependency에 대해 몰랐는데, 최근 UI 라이브러리를 개발하면서 이에 대해 학습하였습니다.
UI 라이브러리는 React를 사용하여 개발했습니다. 그런데 이 라이브러리를 설치하는 프로젝트에도 이미 React가 설치되어 있다면, React가 중복으로 설치되는 문제가 발생합니다.
이 같은 문제를 해결하는 것이 peer dependency입니다.
peer dependency는 "이 라이브러리를 사용하려면 특정 패키지가 필요합니다"라고 명시하는 방법입니다. 패키지를 직접 포함하지 않고. 사용자가 이미 설치했을 것으로 기대하는 의존성을 표시합니다.
실제로 프로젝트에 적용한 방법을 통해 설명하겠습니다.
프로젝트 예시
peer dependency 적용 전
peer dependency를 적용하기 전에 제 UI 라이브러리의 package.json을 보면 다음과 같이 돼있습니다.
{
...
"dependencies": {
"@vanilla-extract/css": "^1.17.4",
"@vanilla-extract/vite-plugin": "^5.1.1",
"clsx": "^2.1.1",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
...
}
...
}
이 UI 라이브러리의 개발에 사용된 react와 react-dom이 dependencies 필드에 있습니다.
이 상태에서 누군가가 이 UI 라이브러리를 설치하면 어떻게 될까요?
node_modules/
react@19.1.0 ← 프로젝트에 이미 있던 React
react-dom@19.1.0
@runzipper/ui/
node_modules/
react@19.2.0 ← UI 라이브러리가 설치한 React (중복!)
react-dom@19.2.0 ← (중복!)
dependencies에 명시된 패키지는 라이브러리 설치 시 함께 설치되기 때문에, React가 중복으로 설치됩니다. 이는 디스크 공간 낭비는 물론, React의 여러 인스턴스로 인한 런타임 에러를 발생시킬 수 있습니다.
peer dependency 적용 후
{
...
"dependencies": {
"@vanilla-extract/css": "^1.17.4",
"clsx": "^2.1.1"
},
"peerDependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
...
"react": "^19.2.0",
"react-dom": "^19.2.0",
...
}
...
}
이제 사용자가 라이브러리를 설치하면:
프로젝트/
node_modules/
react@19.1.0 ← 하나만 설치됨!
react-dom@19.1.0
@runzipper/ui/ ← React를 포함하지 않음
React가 중복 설치되지 않고, 프로젝트의 React를 공유하여 사용합니다.
그런데 말입니다..? 😅
peer dependency를 적용했을 때랑 하지 않았을 때랑 빌드 결과물의 차이가 나지 않았습니다.
# peer dependency 미적용
dist/ui-style.css 9,207.24 kB │ gzip: 6,850.07 kB
dist/main.mjs 23.58 kB │ gzip: 6.99 kB
dist/ui-style.css 9,207.24 kB │ gzip: 6,850.07 kB
dist/main.umd.js 18.00 kB │ gzip: 6.49 kB
✓ built in 4.03s
# peer dependency 적용
ist/ui-style.css 9,207.24 kB │ gzip: 6,850.07 kB
dist/main.mjs 23.58 kB │ gzip: 6.99 kB
dist/ui-style.css 9,207.24 kB │ gzip: 6,850.07 kB
dist/main.umd.js 18.00 kB │ gzip: 6.49 kB
✓ built in 4.01s
저는 peer dependency를 적용한 버전의 빌드 크기가 당연히 작을 줄 알아서 당황했습니다. 😥
왜 peer dependency 적용 유무와 상관없이 결과물의 크기가 같지?
알고 보니 제가 이전에 vite 설정에서 build 옵션으로 react와 react-dom를 번들에서 제외하도록 설정해 놔서 peer dependency와 관계없이 빌드 결과물에서 제외됐던 겁니다.
rollupOptions: {
# 이 부분
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
},
그래서 peer dependency의 역할에 대해 다시 생각해 보게 되었습니다.
peer dependency의 역할
처음에는 peer dependency가 빌드 크기를 줄여준다고 생각했지만, 실제로는 그렇지 않았습니다.
peer dependency에 라이브러리를 명시한다고 해당 라이브러리가 빌드에서 제외되는 게 아닙니다.
peer dependency와 빌드 설정은 서로 다른 목적을 가지고 있습니다:
Peer Dependency의 역할
- 패키지 설치 시 중복을 방지
- 호환되는 버전을 명시하여 버전 충돌 방지
- 사용자에게 "이 버전이 필요합니다"라고 알림
Vite의 external 설정 역할
- 빌드 시 번들에서 제외
- 번들 크기를 실제로 줄임
- 외부 패키지로 처리하여 런타임에 로드
따라서 번들 크기를 줄이는 것이 목적이면 적절한 번들러 설정과 peer dependency 명시 둘 다 필요합니다.
'npm' 카테고리의 다른 글
| [npm] Github packages로 private package 배포하기 (0) | 2025.12.01 |
|---|---|
| [npm] npm에 node.js cli 프로그램 배포하기 (0) | 2025.11.23 |