문제
admin, web 두 앱을 모노레포로 운영하다 보니 react, typescript, eslint 같이 공통으로 쓰는 패키지들의 버전이 각자 package.json에 따로 선언되어 있었다.
이게 지금 당장 문제가 되진 않지만, 버전을 올릴 때마다 파일을 일일이 찾아다니며 수정해야 하고, 수정하는 시점이 달라지면 앱마다 다른 버전이 설치될 수도 있다. 특히 typescript는 minor 버전만 달라져도 타입 추론 결과가 다르게 나올 수 있어서 이게 꽤 불편한 문제가 될 수 있다고 판단했다.
pnpm Catalog
pnpm 9.5+에서 지원하는 기능으로, pnpm-workspace.yaml에 패키지 버전을 한 번만 선언해두고, 각 패키지에서 "catalog:"로 참조하는 방식이다. 버전을 한 곳에서만 관리할 수 있다.
해결 과정
1. pnpm-workspace.yaml에 catalog 선언
catalog:
typescript: "~5.9.3"
eslint: "^9.39.4"
"@eslint/js": "^9.39.4"
prettier: "^3.8.1"
zod: "^3.24.0"
react: "^19.2.4"
react-dom: "^19.2.4"
"@types/react": "^19.2.14"
"@types/react-dom": "^19.2.3"
typescript만 ~(patch만 허용)로 고정했는데, 나머지 패키지들은 minor 업데이트가 크게 영향을 주지 않지만 typescript는 minor 버전에도 타입 추론이 달라질 수 있어서다.
2. 각 패키지에서 catalog:로 참조
"dependencies": {
"react": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"typescript": "catalog:",
"eslint": "catalog:"
}
catalog: 하나면 끝. pnpm install하면 yaml에 선언된 버전으로 알아서 설치된다.
3. @ddd/api의 zod는 peerDependency로
packages/api에서 zod 스키마를 export하고, admin/web이 그걸 import해서 쓰는 구조인데, 만약 양쪽이 각자 zod를 dependencies로 가지면 zod 인스턴스가 두 개 생긴다. 그러면 같은 스키마인데 서로 다른 zod에서 만들어진 것으로 인식되는 문제가 생길 수 있다.
그래서 packages/api에서는 peerDependencies로만 선언하고, 실제 설치는 사용하는 앱(admin, web)이 하도록 했다.
// packages/api/package.json
"peerDependencies": {
"zod": "catalog:"
},
"devDependencies": {
"zod": "catalog:" // 로컬 개발용
}
배운 점
dependencies, devDependencies는 익숙했는데 peerDependencies는 "선언만 하고 설치는 쓰는 쪽에 위임한다"는 개념이 처음엔 좀 낯설었다. 근데 라이브러리 관점에서 생각하니 이해가 됐다. 내 패키지를 누군가 가져다 쓸 때 인스턴스가 두 개 생기는 걸 막으려면 peerDependency가 맞는 선택이다.
그리고 catalog syntax가 catalog:react가 아니라 catalog:(콜론만)라는 것도 처음에 헷갈렸다. catalog:react는 "react라는 이름의 named catalog"를 참조하는 거고, default catalog의 react 키를 참조하려면 그냥 "react": "catalog:"로 써야 한다.
'프론트엔드' 카테고리의 다른 글
| 첫 오픈소스 기여 (feat. HeroUI & react-spectrum): NumberField 버그를 고쳐봤다 (1) | 2026.04.10 |
|---|---|
| [프론트엔드] orval vs hey-api: OpenAPI 코드 생성 라이브러리 비교 (0) | 2026.04.04 |
| [버그 픽스] 메뉴 토글 시 로고가 사라지는 문제 분석: SVG clipPath 충돌 사례 (0) | 2026.03.18 |
| [프론트엔드] 접근성을 고려한 컴포넌트 설계 (Dropdown) (0) | 2025.06.24 |
| [프론트엔드] Next.js(15)에 MSW 도입하기 (0) | 2025.06.18 |