여기어때 항공 프론트엔드 팀이 공용 컴포넌트 라이브러리 배포 시 스타일 격리를 위해 Tailwind prefix yf-를 도입했다가 tailwind-merge가 충돌 감지를 못 하는 문제를 발견하고, 2세대에 걸쳐 해결한 과정을 다룬다. 최종적으로 twMerge의 classGroups와 conflictingClassGroups에 yf- 접두어 유틸리티를 직접 등록하는 방식을 선택했다.
핵심 포인트- twMerge는 bg-로 시작하는 클래스를 background 그룹으로 인식하는데, yf-bg-는 bg-로 시작하지 않아 알 수 없는 문자열로 취급하며 두 클래스 모두 살아남는다. 빌드 에러도 타입 에러도 없이 조용히 깨진다.
- 1세대 해법(prefix 제거 → twMerge → 재부착)은 커스텀 유틸리티(자체 타이포 클래스 등)를 twMerge가 인식하지 못해 문제의 절반만 해결했다.
- 2세대 해법은 twMerge에 yf- 접두어 유틸리티를 classGroups와 conflictingClassGroups에 직접 등록하는 방식("속이지 않고 가르친다")으로 근본 해결했다.
- yf-text- 계열은 크기·정렬·오버플로·데코레이션·색상 5개 그룹으로 분리해야 하며, catch-all인 색상 그룹은 반드시 마지막에 등록해야 한다.
- padding/margin의 단방향 충돌 관계(p는 px·py·pt... 를 지우지만 px는 p를 지우지 않는다)를 conflictingClassGroups에 명시적으로 반영했다.
상세 정리- 배경: 공용 컴포넌트 라이브러리 배포 시 스타일 격리를 위해 Tailwind prefix yf-를 도입했다. 사내 기존 Vue2 라이브러리는 twl- 사용 중이었다.
- 문제 발견: twMerge('yf-bg-blue-500 yf-bg-red-500')가 두 클래스를 모두 출력한다. bg-로 시작하지 않으니 twMerge가 분류를 못 하고, 빌드·타입 에러 없이 조용히 두 스타일이 적용된다.
- 선택지 검토: prefix 포기(라이브러리 격리 요건 위반), twMerge 포기·인라인 style(근본 해결 아님), CSS-in-JS(Tailwind 자산 포기) 모두 제외하고 twMerge에 prefix 등록을 채택했다.
- 1세대(prefixTwMerge): prefix 제거 → 일반 twMerge → prefix 재부착. 커스텀 유틸리티(yds6-TypoUi-14 같은 자체 타이포)는 prefix를 떼도 twMerge가 모르므로 문제의 절반만 해결.
- 2세대 핵심: ALL_UTILITY_KEYS를 순회하며 classGroups에 그룹 이름과 isAny 매처를 등록하고 conflictingClassGroups에 같은 그룹끼리 충돌 관계를 정의했다.
- yf-text- 충돌: yf-text-14(크기), yf-text-center(정렬), yf-text-ellipsis(오버플로), yf-text-underline(데코레이션), yf-text-content-primary(색상)가 모두 yf-text-로 시작해 5개 그룹으로 분리했다. catch-all 색상 그룹은 반드시 마지막에 등록해야 다른 그룹을 먼저 매칭한다.
- yf-border- 충돌: yf-border-t(두께)와 yf-border-border-primary(색상)를 분리 등록했다.
- padding/margin 단방향 관계: p → px·py·pt·pb·pl·pr 지움, px → pl·pr 지움, py → pt·pb 지움. 단 px가 p를 지우면 위아래 패딩이 사라지므로 역방향 충돌은 등록하지 않았다.
- 커스텀 브레이크포인트: twMerge는 변형자(variant)를 이름이 아니라 "앞에 붙은 수식어 묶음이 같은가"로 판정하므로 mobile:·desktop: 등 커스텀 브레이크포인트는 자동 처리됐다.
- 사용 인터페이스: 템플릿 태그 tw``로 감싸 tv()와 결합하며, 컴포넌트에서 tw`yf-flex yf-items-center yf-gap-8` 형태로 사용한다.
- 남은 한계: classGroups를 수동 유지해야 하며, 새 유틸리티 등록을 빠뜨리면 조용히 안 먹는 문제가 재발할 수 있다.
왜 읽나Tailwind prefix 도입 후 tailwind-merge가 작동하지 않는 문제를 겪는 팀에게 classGroups 직접 등록 패턴과 text-·border-·padding/margin의 충돌 분류 전략을 구체적으로 제공한다.