'별거 아니겠지'라고 생각했던 디자인 시스템 NPM 배포가 어떻게 3주간의 삽질로 이어졌는지, 그리고 그 과정에서 배운 타협의 기술. 사내에서만 쓰던 패키지를 세상에 내놓기까지를 다루는 배포 시리즈의 프롤로그입니다.
프롤로그: "별거 아니겠지"의 착각
타팀 기획자님이 내 자리로 다가왔다.
"개발자님, 저희 팀에서도 그 디자인 시스템 쓸 수 있을까요? 버튼이랑 인풋 컴포넌트가 정말 예쁘던데..."
당시 디자인 시스템은 완성해둔 참이었다.
모노레포 안에서는 잘 돌아가고 있었다.
Button, Input, Card... 약 60개 정도?
"아, 그거요? 별거 아니에요."
나는 자신만만하게 대답했다.
"NPM에 올리기만 하면 되니까 하루면 될 것 같은데요?"
기획자님의 환한 미소가 아직도 기억난다.
"정말요? 그럼 이번 주 안에 가능할까요?"
"네, 금방이에요!"
그리고 3주가 지났다.
하루라고 했던 작업은 21일이 걸렸다.
그 사이에 나는:
빌드 도구와 10일을 싸웠고
20MB 괴물 패키지를 만들어냈고
CSS 충돌로 머리를 쥐어뜯었고
무한 재귀 배포를 중단시켰다
지금 돌아보면 그날의 나에게 말해주고 싶다.
"별거 아닌 일은 없어. 특히 배포는."
그땐 좋아 보였는데...
완벽한 계획 (예상 기간: 1일)
머릿속으로 그린 계획은 완벽했다.
트리셰이킹
CSS 번들
Type 지원
배포 문서
자동 배포 시스템
"배포 말고는 이미 잘 되어 있는거니 별 문제 없겠지?"
과연 이 계획대로 될까?
우리 프로젝트 상황
모노레포 구성
신규 프로젝트와 디자인 시스템을 동시에 구현
코드 공유와 의존성 관리의 효율성 고려
향후 다른 팀으로의 확장 가능성
기술 스택 선택: Mantine + Panda CSS
당시 팀 상황을 고려하면 현실적인 선택이었다:
개발/디자인 리소스 부족
디자인 시스템 구축 경험 부족
Tailwind 문법에 대한 팀 내 선호도 문제
Mantine의 높은 완성도와 Panda CSS의 유연성이 우리 팀에 적합해 보였다.
현재 프로젝트 구조
monorepo/
├── design-system # 메인 디자인 시스템
└── packages/
├── @package/core # HTTP 클라이언트, 상태 코드
├── @package/constants
├── @package/entities
└── @package/service
@tailwind base;@tailwind components;@tailwind utilities;@layer components{.button{background: red !important;padding: 10px !important;}}/* layer 없이 직접 작성된 스타일들 */.some-legacy-class{margin: 20px !important;color: blue !important;}
"...!important 지옥이네."
온갖 하드코딩 CSS가 !important로 도배되어 있었다.
우리 디자인 시스템 스타일이 전부 덮어씌워지고 있었다.
"이거... 어떻게 하지?"
Tailwind의 @layer 문법도 섞여있고,
레거시 스타일도 있고,
우리 Mantine + Panda CSS까지.
세 개의 CSS 시스템이 충돌하고 있었다.
@layer로 우선순위 제어
CSS @layer 문법을 알게 됐다.
css
/* 레이어 우선순위 설정 - Mantine을 낮은 우선순위로 배치 */@layer reset, base, tokens, recipes, utilities, tailwind, mantine, panda-reset, panda-base, panda-tokens, panda-recipes, panda-utilities;/* Mantine CSS를 낮은 우선순위 layer에 배치 */@import'@mantine/core/styles.css'layer(mantine);/* Tailwind도 별도 layer로 관리 */@layer tailwind{@tailwind base;@tailwind components;@tailwind utilities;}
이 방법이 유일하게 원하던 대로 된 해결책이었다.
결과:
✅ !important 없이도 스타일 제어 가능
✅ Mantine, Tailwind, Panda CSS 모두 공존 가능
✅ 우선순위 디버깅이 훨씬 쉬워짐
이러면 전부 다 잘 되나?
타협 #3: 완벽한 호환
현실: 다른 프레임워크 + 다른 CSS 라이브러리 + !important
근거: 서비스가 운영 중이어서 단번에 구조를 뒤엎는 것이 위험. 어쩔 수 없는 레거시는 점진적으로 수정하기로.
결정: 점진적 마이그레이션
디자인 시스템을 적용하면서 수동으로 수정해야 했다.
타협안:
⚠️ !important 문제가 남음
⚠️ 기존 스타일 일부 깨짐
실용적 결정:
✅ 실 서비스에 적용은 가능
어쩔 수 없는 레거시 청산으로 하나씩 수정하기로
"완벽하진 않지만, 돌아간다."
3주차-2: 배포 자동화 - "마지막까지 순탄하지 않았다"
이제 배포 파이프라인을 만들자!
로컬 테스트도 성공했다. 실 서비스 적용도 가능해졌다. 이제 자동 배포 시스템을 만들 차례였다.
목표:
GitHub Actions 워크플로우가 develop 브랜치 PR 이벤트에 각 패키지의 버전 체크
변경할 버전이 있다면 version update 할 정보를 담아 json에 저장
머지(push) 할 때 version update commit 생성
npm scope 문제 - 대참사의 시작
GitHub npm에 배포를 시도했을 때 예상치 못한 문제가 발생했다.
403 error
권한 부족?
원인:
패키지 이름(name)이 npm scope 규칙에 맞지 않음. @org/packagename 형식이어야 했다.
당당하게 지었던 패키지 이름이 발목을 잡았다.
해결 방법 고민:
GitHub 조직 새로 만들기 → 복잡하고 시간 소요
사설 서버 설치 ex) Nexus, etc
패키지 이름 변경 ✅ → 관련 파일의 import 구문 변경
결국 패키지 이름을 scope 규칙에 맞게 변경했다. 모든 import 문을 수정해야 했다.
GitHub Actions 무한 재귀의 공포
자동 배포 시스템도 거의 다 만들었다.
Changeset으로 버전 관리도 하고,
GitHub Actions로 자동 배포도 설정했다.