컬리 KLDS 기반 React 컴포넌트 라이브러리 Kitchen이 UMD 빌드 + 28개 컴포넌트별 패키지 구조 때문에 트리셰이킹이 안 되던 문제를, 실제 사용 방식(단일 배포)에 맞춰 ESM 단일 패키지로 재설계한 기록이다.
핵심 포인트- 모든 컴포넌트가 kitchen-core에서 재내보내기되는 단일 진입점 + UMD/CommonJS 혼합이라, 일부만 import해도 전체가 번들에 포함되고 번들러 정적 분석이 불가능했다.
- ESM-only로 전환하고 exports 필드로 노출 범위를 명시해 구조 자체만으로 트리셰이킹을 보장했다.
- 28개 멀티 패키지를 단일 패키지로 합쳐(실제로도 단일 배포 단위였음) 소스 기준 의존 관계를 명확화했다.
- 디자인 토큰(색상·타이포·간격)을 kitchen-foundation으로 분리해 Desktop/Mobile 중복을 제거했다.
- 결과는 빌드 60.93초→6.94초(8.8배), 번들 내 Kitchen 코드 1.61MB→162.5KB(약 90% 감소)다.
상세 정리- 초기 설계: 다양한 실행 환경(레거시 웹) 재사용을 노려 UMD 빌드 + 컴포넌트별 독립 패키지를 채택했다.
- 문제 1(트리셰이킹 불가): 단일 진입점 재내보내기 + UMD/CommonJS 혼합으로 정적 분석이 불가능해 일부 import에도 전체가 포함됐다.
- 문제 2(구조·사용 불일치): 28개 패키지 구조인데 배포는 단일 진입점이고 참조가 빌드 산출물 기준이라 Storybook propTypes 자동 추론이 안 되고 테스트 모킹이 복잡했다.
- 문제 3(DX 저하): Cold start 86.34초, 빌드 60.93초, 새 컴포넌트 추가 시 번들 영향을 먼저 고려하는 악순환이었다.
- 판단 기준: 실제 사용 방식과 구조 일치, 번들러 정적 분석 가능, 단기 성능보다 중장기 유지보수 우선.
- 방안 1(ESM 전환): 모든 사용처가 웹 번들러 기반 React임을 확인하고 CommonJS·UMD를 제거, exports 필드로 노출을 명시했다.
- 방안 2(단일 패키지): 컴포넌트별 버전·배포를 실제로 안 했고 패키지별 설정 유지 비용·deprecated 누적이 커서 단일 패키지로 합쳤고, 빌드 시간 증가는 현 규모에서 안정적임을 확인했다.
- 방안 3(foundation 분리): 색상·타이포·간격 토큰을 단일 책임으로 중앙화해 Desktop/Mobile 변경 누락 위험을 없앴다.
- 미적용: Rollup 등 번들러 전환은 영향 범위를 고려해 구조·배포 정리를 우선하고 향후 재검토로 미뤘다.
- DX 결과(3회 평균): 빌드 60.93→6.94초(88.6%), Cold 86.34→20.87초(75.82%), Hot은 HMR 즉시, 코드 2만8천 줄 감소.
- 번들 결과: 측정 서비스 내 Kitchen 코드 1.61MB→162.5KB(89.97%), 전체 컴포넌트 페이지 136KB vs 최소 페이지 1.73KB로 트리셰이킹이 정상 동작했다.
- 트레이드오프: ESM-only는 구 Node·UMD 사용처를 미지원하고, 단일 패키지는 개별 컴포넌트 버저닝이 불가하며 한 컴포넌트 변경이 전체 배포를 트리거한다.
왜 읽나사내 디자인 시스템/컴포넌트 라이브러리의 번들 크기·트리셰이킹·DX 문제를 겪는 프론트엔드 개발자에게 ESM·단일 패키지·토큰 분리의 의사결정 레퍼런스.