모노레포 환경에서 공통 UI 패키지(@repo/ui)를 구축할 때 각 패키지가 독립적으로 스타일을 빌드하게 만든다면, sm:px-10 같은 반응형 클래스가 무시되거나, 스타일 우선순위가 뒤엉키는 'Cascade Conflict'가 발생합니다.
이번 트러블슈팅을 통해 CSS Cascade(계단식 적용) 원리와 Tailwind v4의 빌드 메커니즘, 그리고 모노레포에서의 정확한 경로 설정의 중요성을 알아봅니다.
1. 문제 증상
- 상황: packages/ui 내부의 Modal 컴포넌트에 px-5.25 sm:px-10.75를 적용함.
- 현상: 화면 너비가 640px(sm) 이상임에도 불구하고, 개발자 도구에서 sm:px-10.75에 취소선이 그어지고 px-5.25가 최종 적용됨.
- 특이사항: sm:!px-10.75처럼 !(important)를 붙여야만 정상 작동함.
2. 원인 분석
2.1 CSS Cascade Order (선언 순서의 역전)
CSS는 나중에 선언된 스타일이 우선 적용됩니다.
미디어 쿼리는 그 자체로 가중치(Specificity)를 높여주지 않습니다.
- 문제: packages/ui와 apps/homepage 양쪽에서 @import "tailwindcss";를 호출하고 있었습니다.
- 결과: 브라우저는 두 개의 별도 CSS 파일(index.css, globals.css)을 로드합니다. 이때 globals.css의 sm: 미디어 쿼리보다 index.css의 일반 px- 클래스가 더 나중에 로드되면, 브라우저는 미디어 쿼리 조건이 맞더라도 나중에 나타난 일반 클래스를 렌더링하게 됩니다.
2.2 Tailwind v4의 JIT 엔진 스캔 범위와 @source
Tailwind v4는 @import "tailwindcss";가 선언된 프로젝트 내부 파일만 기본으로 스캔합니다.
- 문제: homepage 앱 빌드 시, 외부 워크스페이스인 ../../packages/ui 폴더는 스캔 대상에서 제외됩니다.
- 결과: sm:px-10.75 같은 클래스는 실제 CSS 코드로 생성조차 되지 않거나, 엉뚱한 순서로 배치됩니다.
3. 해결 방법: 단일 엔진 통합 및 정확한 경로 명시
단계 1: UI 패키지에서 Tailwind 엔진 제거하기
packages/ui는 스타일을 생성하는 곳이 아니라 스타일의 가이드를 제공하는 곳이어야 합니다.
중복 엔진 실행을 막기 위해 @import "tailwindcss";를 제거합니다.
/* packages/ui/style.css */
@import "@repo/tailwind-config";
/* @import "tailwindcss"; <- 중복 방지를 위해 삭제함
단계 2: 최종 앱에서 외부 경로(@source) 명시

기본적으로 Tailwind는 빌드 명령어를 실행하는 현재 작업 디렉토리(CWD)를 기준으로 파일을 찾습니다. 하지만 모노레포 루트에서 모든 앱을 한꺼번에 빌드하는 경우, 각 앱의 소스 위치가 꼬일 수 있습니다.
이때 @import 문에 source() 함수를 사용하여 스캔의 시작점을 강제로 지정할 수 있습니다.
앱의 globals.css에서 Tailwind v4 엔진을 실행하고, 모노레포 루트를 거쳐 UI 패키지까지 도달하는 정확한 상대 경로를 알려줘야 합니다.
/* apps/homepage/src/styles/globals.css */
// 앱 내부에서 정의된 파일을 임포트하기
@import "tailwindcss";
@import "@repo/tailwind-config";
@source "../../../../packages/ui/src/**/*.{ts,tsx}";
단계 3: CSS 임포트 순서 최적화 (Priority)
모든 스타일 유틸리티가 마지막에 배치되어 우선순위를 가질 수 있도록 layout.tsx에서 임포트 순서를 조정합니다.
// apps/homepage/src/app/layout.tsx
import "@repo/ui/style.css"; // UI 패키지 기본 스타일 (먼저)
import "@/styles/globals.css"; // Tailwind 유틸리티가 포함된 최종 파일 (나중에 임포트)
4. 마치며
이번 트러블슈팅을 통해 얻은 가장 큰 교훈은 디자인 시스템 패키지는 스타일을 직접 빌드(Build)하는 주체가 아니라, 앱이 스타일을 렌더링할 수 있도록 재료를 제공하는 역할이어야 한다는 점입니다.
테일윈드 엔진은 최종 서비스에서 단 한 번만 돌아야 하며, 엔진이 파편화되지 않아야 합니다.
모노레포 환경에서 TailwindCSS v4 를 사용하는 분들에게 도움이 되길 바라며 글을 마칩니다.
'프론트엔드' 카테고리의 다른 글
| URL 상태를 결합한 선언적 데이터 페칭 구현하기 (0) | 2026.03.09 |
|---|---|
| @use-funnel로 복잡한 온보딩 흐름 제어하기 (feat. Zod) (1) | 2026.02.23 |
| 프로젝트 통합으로 생산성 높이기: Turborepo 도입 및 모노레포 마이그레이션 여정 (0) | 2026.02.22 |
| Next.js 프로젝트에서 Storybook 도입해보기 (0) | 2026.01.29 |
| 시각장애인을 위한 모달 컴포넌트 웹 접근성 개선기 (Focus Trap 적용기) (0) | 2026.01.29 |