Developer/React

디자인 시스템을 개발하면서 알게 된 peerDependencies의 역할

jaddong 2024. 6. 10. 20:22
320x100

package.json에서는 우리가 해당 프로젝트에 대한 정보 및 의존 정보들을 작성하게된다.

name, verson, repository, scripts, dependencies, devDependencies 등의 정보가 json형태로 존재한다.

package.json에서 대부분 쓰는 항상 항목들만 쓰는 경우가 많을 것이다.

하지만 만약 공통 모듈 패키지나 라이브러리를 개발중이라면 peerDependencies에 집중할 필요가 있다는 걸 알게되었다.

 

 

1. 문제 발견

my-app 리액트 프로젝트에서 내가 개발한 라이브러리 my-packge와 another-package를 설치해 사용하려고했다.

아래와 같은 package.json를 작성하였다.

 

{
  "name": "my-app",
  "version": "1.0.0",
  "dependencies": {
    "react": "^17.0.0"
    "my-package": "^1.0.0",
    "another-package": "^1.0.0"
  }
}

 

 

my-app에서 yarn install을 하니 아래와 같은 warning을 발견할 수 있었다.

 

yarn install

warning "my-package@1.0.0" has unmet peer dependency "react@^17.0.0".
warning "another-package@1.0.0" has unmet peer dependency "react@^17.0.0".

 

 

하지만 동작에는 크게 문제가 없어보였다. 아마 리액트 버전이 같아서 그럴지도 모르겠다. 🤷‍♀️

다른 경우를 찾아보니 실제로 종속성 에러가 나는 경우도 있었다.

하지만 warning이나 error는 가능하면 깨끗하게 없애고 싶어진다. 😂 그래서 찾게 된 peerDependencies!!

 

2. 문제 파악하기

"Peer dependencies는 특정 패키지가 다른 패키지를 필요로 하지만, 그 패키지를 직접 포함하지 않고, 상위 프로젝트(패키지를 설치하는 프로젝트)에서 해당 의존성을 설치하도록 요구하는 방식" 이라고 한다.

 

이렇게만 보면 무슨 소린지 모를 수 있으니 직접 peerDependencies를 작성했을 때와 작성하지 않았을 때를 비교해보도록 했다.

 

 

peerDependencies를 작성하지 않았을 때 의존성 트리 확인하기

내가 만든 라이브러리인 my-package와 another-package는 react "^17.0.0"을 의존성으로 가지고 있고

my-app 도 똑같이 react "^17.0.0"를 의존하고 있다.

{
  "name": "my-app",
  "version": "1.0.0",
  "dependencies": {
    "react": "^17.0.0"
    "my-package": "^1.0.0",
    "another-package": "^1.0.0"
  }
}

 

{
  "name": "my-package",
  "version": "1.0.0",
  "dependencies": {
    "react": "^17.0.0"
  }
}
{
  "name": "another-package",
  "version": "1.0.0",
  "dependencies": {
    "react": "^17.0.0"
  }
}

 

 

npm ls react 를 커맨드창에 쳐보자.

위처럼 peerDependencies를 작성하지 않았을 때의 의존성 트리 살펴보면 아래와 같다.

my-package의 node_moules에도 another-package의 node_moudules 에도 똑같이 react가 설치되어진다! 무려 세 번!

 

my-app
├── node_modules
│   ├── my-package
│   │   └── node_modules
│   │       └── react (17.0.0) 
│   └── another-package
│   │   └── node_modules
│   │       └── react (17.0.0) 
│   └── react (17.0.0)
└── package.json

 

 

 

peerDependencies를 작성했을 때 의존성 트리 확인하기

peerDependencies는 이 라이브러리를 사용하게 될 프로젝트에게, react ^17.0.0 버전을 사용해주세요! 라고 알려주는 것과 비슷하다.

 

{
  "name": "my-package",
  "version": "1.0.0",
  "dependencies": {
    "react": "17.0.2",
  }
  "peerDependencies": {
    "react": "^17.0.0"
  }
}

 

{
  "name": "another-package",
  "version": "1.0.0",
  "dependencies": {
    "react": "17.0.2",
  }
  "peerDependencies": {
    "react": "^17.0.0"
  }
}

 

 

npm ls react 를 커맨드창에 쳐서 프로젝트에서 의존성 트리를 살펴보면 react가 하나로만 node_modules에 들어가게 된다.

deduped 라고 중복무시된 것을 확인할 수 있다.

 

my-app
├── node_modules
│   ├── my-package
│   │   └── node_modules
│   │       └── react (17.0.0) deduped
│   └── another-package
│   │   └── node_modules
│   │       └── react (17.0.0) deduped
│   └── react (17.0.0)
└── package.json

 

 

 

차이 요약

 

  • Peer Dependencies 사용 전: 각 패키지가 자체적으로 필요한 의존성을 포함하여 node_modules 폴더가 중복 설치된 라이브러리로 인해 커진다.
  • Peer Dependencies 사용 후: 상위 프로젝트에서 의존성을 관리하여 중복 설치를 방지하고, node_modules 폴더의 크기를 줄인다.

 

 

실제 코드로 라이브러리의 빌드 결과물에서 확인해보기

라이브러리에 peerDependencies 없이 빌드했을 때

my-package와 another-package에 peerDependencies에 react와 react-router-dom 를 넣지 않았을 때 dist/index.js 결과물을 보면 아래와 같다.

"var reactExports = {} ... " 로 시작하는 react 코드가 빌드 결과에 포함되어 있는 걸 확인할 수 있다. 

 

 

이 경우 dist/index.js 을 용량은 180KB로 측정되었다.

 

 

라이브러리에 peerDependencies 에 react, react-router-dom 를 추가하여 빌드했을 때

my-package와 another-package에 peerDependencies에 react와 react-router-dom를 넣고 빌드를 하면, react가 아래와 같이 한 줄로만 보여진다.

"var reactExports = {} ... " 로 시작하던 약 2493줄의 리액트 코드가 var React = require('react') 으로 바뀌게된다.

 

 

그러다보니 index.js 파일의 용량이 확 줄 수 밖에 없는 것이다.

 

 

결론

결론적으로, peer dependencies를 사용하면 패키지 간의 중복 의존성을 줄이고, 빌드된 결과물의 용량을 효율적으로 관리할 수 있었다.

react와 react-router-dom만 peer dependencies에 추가해도 라이브러리 번들 결과를 약 50%나 줄일 수 있었다.

 

또한 의존성 충돌을 방지하기 위해 의존성 트리를 확인하는 것이 좋을 것 같고, 특히나 react 가 포함된 라이브러리를 리액트 프로젝트에 사용하는 경우 꼭 확인해야할 것으로 보인다.

 

 

반응형