문제 상황
Tailwind CSS를 v3에서 v4로 업그레이드했더니 다음과 같은 오류들이 발생함:
- PostCSS 플러그인 오류:
It looks like you're trying to use 'tailwindcss' directly as a PostCSS plugin - Unknown utility class 오류:
Cannot apply unknown utility class 'border-border' - 최대 재귀 깊이 초과:
Exceeded maximum recursion depth - CSS 변수 문법 오류:
w-[--sidebar-width]가 작동하지 않음 - 사이드바 레이아웃 깨짐: 메인 콘텐츠 위에 사이드바가 겹쳐짐
문제 1: PostCSS 플러그인 오류
오류 메시지
1
2
| [plugin:vite:css] [postcss] It looks like you're trying to use 'tailwindcss' directly as a PostCSS plugin.
The PostCSS plugin has moved to a separate package.
|
원인
Tailwind CSS v4부터 PostCSS 플러그인이 별도 패키지(@tailwindcss/postcss)로 분리됨.
해결 방법
1. 패키지 설치
1
| pnpm add -D @tailwindcss/postcss
|
2. PostCSS 설정 변경
Before (v3):
1
2
3
4
5
6
7
| // postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
|
After (v4):
1
2
3
4
5
6
| // postcss.config.js
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
|
autoprefixer는 v4에 내장되어 있으므로 제거해도 됨.
문제 2: Unknown Utility Class 오류
오류 메시지
1
| [postcss] tailwindcss: Cannot apply unknown utility class 'border-border'
|
원인
Tailwind v4에서 @tailwind 지시어 대신 @import "tailwindcss"를 사용해야 함.
해결 방법
Before (v3):
1
2
3
4
| /* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
|
After (v4):
1
2
| /* globals.css */
@import "tailwindcss";
|
주의: @import "tailwindcss"는 반드시 파일 최상단에 위치해야 함.
문제 3: 최대 재귀 깊이 초과
오류 메시지
1
| [plugin:@tailwindcss/vite:generate:serve] Exceeded maximum recursion depth while resolving 'tailwindcss/utilities'
|
원인
node_modules 손상@theme 블록과 tailwind.config.ts 충돌@layer 내부의 순환 참조
해결 방법
1. node_modules 완전 재설치
1
2
| rm -rf node_modules pnpm-lock.yaml
pnpm install
|
2. 빌드 캐시 삭제
대부분의 경우 깨끗한 재설치로 해결됨.
문제 4: @layer와 @apply 호환성 문제
원인
Tailwind v4는 @layer와 @apply 지시어를 레거시로 간주하며, CSS-first 접근 방식을 권장함.
해결 방법
모든 @layer와 @apply를 명시적 CSS로 변환해야 함.
Before (v3 - @apply 사용)
1
2
3
4
5
6
7
8
9
10
11
12
13
| @layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground antialiased;
}
h1 {
@apply text-4xl font-bold;
}
}
|
After (v4 - 명시적 CSS)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| * {
border-color: hsl(var(--border));
}
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1 {
font-size: 2.25rem;
line-height: 2.5rem;
font-weight: 700;
}
|
변환 가이드
| v3 (@apply) | v4 (명시적 CSS) |
|---|
@apply text-primary | color: hsl(var(--primary)); |
@apply bg-background | background-color: hsl(var(--background)); |
@apply border-border | border-color: hsl(var(--border)); |
@apply text-sm | font-size: 0.875rem; line-height: 1.25rem; |
@apply font-bold | font-weight: 700; |
문제 5: CSS 변수 문법 변경
오류
Arbitrary value에서 CSS 변수를 사용할 때 스타일이 적용되지 않음.
1
2
| // ❌ v4에서 작동 안 함
<div className="w-[--sidebar-width]">
|
원인
Tailwind v4에서 CSS 변수를 arbitrary value로 사용할 때 var() 함수가 필수가 됨.
해결 방법
Before (v3)
1
2
| <div className="w-[--sidebar-width]">
<div className="h-[--header-height]">
|
After (v4)
1
2
| <div className="w-[var(--sidebar-width)]">
<div className="h-[var(--header-height)]">
|
사이드바 레이아웃 수정 예시
1
2
3
4
5
6
7
| // Sidebar.tsx
<div className="relative w-[var(--sidebar-width)] bg-transparent">
{/* Spacer div - 공간 확보 */}
</div>
<div className="fixed w-[var(--sidebar-width)]">
{/* 실제 사이드바 컨텐츠 */}
</div>
|
주의: style 속성에서는 var() 없이 사용 가능:
1
| <div style={{ "--sidebar-width": "16rem" } as React.CSSProperties} />
|
문제 6: 커스텀 유틸리티 클래스 미생성
문제
프로젝트에서 사용하는 text-muted-foreground, bg-accent 등의 클래스가 생성되지 않음.
원인
v4에서 @import "tailwindcss" 사용 시 tailwind.config.ts의 theme.extend.colors가 자동으로 유틸리티 클래스를 생성하지 않음.
해결 방법
필요한 클래스를 globals.css에 직접 정의:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| /* globals.css */
/* Text Color Utilities */
.text-foreground {
color: hsl(var(--foreground));
}
.text-muted-foreground {
color: hsl(var(--muted-foreground));
}
.text-primary {
color: hsl(var(--primary));
}
/* Background Utilities */
.bg-background {
background-color: hsl(var(--background));
}
.bg-muted {
background-color: hsl(var(--muted));
}
.bg-accent {
background-color: hsl(var(--accent));
}
/* Border Utilities */
.border {
border-width: 1px;
}
.border-border {
border-color: hsl(var(--border));
}
|
결과
Before
- PostCSS 플러그인 오류로 빌드 실패
@apply 사용으로 인한 레거시 경고- CSS 변수 문법 오류로 사이드바 레이아웃 깨짐
- 커스텀 유틸리티 클래스 미생성
After
- 빌드 성공 및 모든 오류 제거
- 명시적 CSS로 변환하여 레거시 제거
- CSS 변수 문법 수정으로 레이아웃 정상화
- 필요한 유틸리티 클래스 직접 정의
마이그레이션 체크리스트
1. 패키지 설치
1
| pnpm add -D @tailwindcss/postcss
|
2. PostCSS 설정 변경
1
2
3
4
5
6
| // postcss.config.js
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};
|
3. CSS Import 문법 변경
1
2
| /* globals.css */
@import "tailwindcss";
|
4. @layer와 @apply 제거
- 모든
@layer 블록을 제거 - 모든
@apply 지시어를 명시적 CSS로 변환
5. CSS 변수 문법 수정
\[--var\] → [var(--var)] 형식으로 변경- 프로젝트 전체 검색:
\[-- → [var(--
6. 커스텀 유틸리티 클래스 정의
- 자주 사용하는 클래스를
globals.css에 직접 정의
7. 의존성 재설치
1
2
| rm -rf node_modules pnpm-lock.yaml .vite
pnpm install
|
8. 빌드 테스트
주의할 점
1. @layer와 @apply는 완전히 제거해야 함
Tailwind v4는 CSS-first 접근을 강제하므로, 기존 @apply 방식을 계속 사용하면 경고가 발생함.
2. CSS 변수는 클래스에서만 var() 필수
1
2
3
4
5
| // ✅ 클래스에서는 var() 사용
<div className="w-[var(--sidebar-width)]">
// ✅ style 속성에서는 var() 없이 사용
<div style={{ width: 'var(--sidebar-width)' }}>
|
3. 재귀 오류는 node_modules 재설치로 해결
빌드 중 재귀 오류가 발생하면 node_modules를 삭제하고 재설치하는 것이 가장 확실한 해결책임.
4. 브라우저 캐시 확인
스타일 변경이 반영되지 않으면 브라우저 하드 리프레시(Ctrl + Shift + R)를 시도.
Tailwind CSS v4 마이그레이션은 PostCSS 설정 변경, @apply 제거, CSS 변수 문법 수정이 핵심이었음. 레거시 방식을 완전히 제거하고 CSS-first 접근으로 전환하여 더 명확한 스타일 관리가 가능해짐.
도움이 되셨길 바랍니다! 😀