의존성은 단순히 설치하는 게 아니다
의존성은 단순히 설치하는 게 아니다
npm, Semantic Versioning, 그리고 내부 라이브러리 설계에서의 진짜 고민들
1. 들어가며 – npm install
이 시작일 뿐이라는 걸 알기까지
프론트엔드 개발을 하다 보면 자연스럽게 npm install
이라는 명령어를 매일같이 사용한다.
하지만 이 명령어가 어떻게 동작하는지, 우리가 설치한 패키지들이 실제로 어떤 식으로 애플리케이션과 얽히는지
깊게 이해하려 들면, 꽤 복잡한 세계가 펼쳐진다.
이번 글에서는 단순히 npm의 기초적인 개념을 짚는 걸 넘어서,
내부 라이브러리를 만들면서 직접 마주친 의존성 충돌과 버전 관리의 문제를 정리한다.
2. Semantic Versioning은 정말 안전한가?
npm 생태계는 Semantic Versioning에 기반한 버전 규칙을 사용한다.
- major: 기존과 호환되지 않는 변경
- minor: 호환되며 기능 추가
- patch: 호환되며 버그 수정
그리고 "^1.2.3"
같은 표현은 ^
기호를 통해 minor/patch 범위의 자동 업데이트를 허용한다.
하지만 문제는 0.x
버전대의 패키지다. 예를 들어:
"lodash-es": "^0.14.1"
이 표현은 실제로는 patch 수준이 아닌 minor 버전까지도 깨질 수 있다.
즉, ^0.14.1
은 >=0.14.1 <0.15.0
이 아닌, >=0.14.1 <0.15.0
으로 해석되며, 매우 민감한 업데이트에도 깨질 위험이 있다.
3. dependencies, devDependencies, peerDependencies의 차이는 어디서 드러나는가
dependencies
: 실제 런타임에서 필요한 모듈devDependencies
: 빌드, 테스트, 개발용 도구peerDependencies
: 직접 의존하지 않지만 호환성을 강제하거나, 반드시 외부에서 주입되어야 하는 경우
특히 peerDependencies
는 플러그인 시스템, UI 라이브러리 같은 공통 레이어에서 필수다.
같은 react
를 두 번 설치하거나, styled-components
인스턴스가 중복되면 예기치 않은 에러가 발생하기 때문이다.
4. 내부 라이브러리 개발에서 마주친 의존성의 그늘 – React, Apollo를 예로
공통 컴포넌트를 묶은 내부 라이브러리를 개발하던 중,
react
, @apollo/client
같은 의존성 관리에서 여러 번 충돌을 겪었다.
"dependencies": {
"react": "^18.2.0",
"@apollo/client": "^3.8.0"
}
이 구조는 결국 다음 문제를 일으켰다.
- React 중복 인스턴스 →
Hooks can only be called inside...
오류 - Apollo 캐시 전략 충돌, 타입 mismatching
그래서 아래처럼 설계를 바꿨다:
"peerDependencies": {
"react": "^18.0.0",
"@apollo/client": "^3.8.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false
},
"@apollo/client": {
"optional": true
}
}
react
: 필수, 반드시 외부에서 제공apollo
: 선택적, 특정 컴포넌트에서만 필요
→ 실무에서 유연성과 안정성을 동시에 확보하는 구조였다.
5. peerDependenciesMeta의 힘 – 선택적 의존성과 경고 수준 조절
npm은 peerDependenciesMeta
를 통해 peerDependency
항목을 optional로 지정할 수 있게 해준다.
이를 활용하면 "있으면 좋지만 없어도 된다"는 의존성을 부드럽게 처리할 수 있다.
예:
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
이 구조는 모든 기능을 react-dom에 의존하지 않는 컴포넌트에서 특히 유용하다.
6. 결론 – 의존성은 '통제 가능한 신뢰'를 설계하는 일이다
의존성은 단순히 npm install
로 설치하고 끝내는 게 아니다.
그건 팀과 프로젝트 전반에 걸쳐 신뢰할 수 있는 체계를 설계하는 일이다.
- 언제 어떤 버전을 받아들일지
- 중복 인스턴스가 생기지 않도록 어떤 설계를 취할지
- 선택적 모듈을 어떻게 선언하고 경고 수준을 조절할지
모두가 겪고 있으면서도 명확히 말하지 않았던 이 고민을
하나하나 문서화하고 구조화하는 것이
내부 라이브러리를 팀이 '믿고 쓸 수 있게' 만드는 첫걸음이었다.
🔍 태그 (SEO 키워드)
npm, dependencies, peerDependencies, semantic versioning, 내부 라이브러리, react, apollo, npm install, 패키지 버전 충돌, node_modules, package.json 이해