최근에 Next.js로 개발된 디자인 시스템을 React(Vite) 프로젝트로 옮기는 과정에서 예상치 못한 문제가 발생했습니다. Next.js에서는 잘 동작하던 Tailwind CSS 기반의 커스텀 유틸리티와 @layer, @apply 조합이 Vite 기반 React 프로젝트에서는 제대로 적용되지 않는 현상이었습니다. 이 글에서는 그 원인과 해결 과정을 정리했습니다.
Next.js 프로젝트(fofood-origin)에서 디자인 시스템을 개발할 때,
globals.css(또는 index.css)에 @layer utilities {
.text-body-2-medium {
@apply font-figtree text-base font-medium leading-none tracking-[-0.04em];
}
}
와 같이 커스텀 유틸리티 클래스를 정의하고,
.btn-yellow-solid {
@apply text-body-2-medium ...;
}
처럼 @apply로 재사용하는 방식이 잘 동작했습니다.
이 디자인 시스템을 Vite 기반의 React 프로젝트(design-test)로 그대로 가져와 적용했을 때,
아래와 같은 에러가 발생했습니다.
Error: Cannot apply unknown utility class `text-body-2-medium`.
Next.js는 Tailwind와 PostCSS, 글로벌 CSS를 통합적으로 처리하면서,
@layer utilities에서 정의한 커스텀 유틸리티를 @apply로 사용할 때도
“일반 CSS 클래스”로 인식하여 에러 없이 빌드가 진행되는 경우가 많았습니다.
Vite(React)는 Tailwind의 JIT 엔진이 모든 CSS를 직접 처리합니다.
이때 @apply 안에 들어가는 클래스는 반드시 Tailwind가 “자신이 생성한 유틸리티”여야 하며,
그렇지 않으면 빌드 에러가 발생합니다.
Tailwind 공식 문서에서는
“@apply는 Tailwind가 생성한 유틸리티 클래스에만 사용할 수 있습니다.
@layer에서 정의한 커스텀 유틸리티는 @apply로 사용할 수 없습니다.”
라고 명시하고 있습니다.
즉, Next.js에서만 “운 좋게” 동작했던 것이고,
Vite(React)에서는 공식 정책대로 엄격하게 동작한 것입니다.
src 디렉토리 전체가 포함되어야 Tailwind가 유틸리티를 생성합니다.
fontSize, colors, fontFamily 등 필요한 값을 tailwind.config.js에 추가했습니다.
@apply에서는 반드시 Tailwind 기본 유틸리티만 사용하도록 코드를 수정했습니다.
예를 들어,
.btn-yellow-solid {
@apply font-figtree text-base font-medium ...;
}
처럼 직접 유틸리티 조합을 사용했습니다.
Next.js와 Vite(React)에서 Tailwind CSS의 @layer, @apply, 커스텀 유틸리티 처리 방식이 다릅니다.
Next.js에서는 PostCSS 처리 순서 등으로 인해 커스텀 유틸리티를 @apply로 써도 동작할 수 있지만,
Vite(React)에서는 반드시 Tailwind가 생성한 유틸리티만 @apply에서 사용할 수 있습니다.
디자인 시스템을 여러 환경에서 재사용하려면, Tailwind의 공식 정책에 맞게 커스텀 유틸리티를 관리하고,
@apply에서는 기본 유틸리티만 사용하는 것이 안전합니다.
이 경험을 통해,
프로젝트 환경에 따라 Tailwind CSS의 동작 방식이 달라질 수 있음을 알게 되었고,
공식 문서의 정책을 항상 준수하는 것이 중요하다는 점을 다시 한 번 깨달았습니다.