본문 바로가기

프로그래밍

Tailwind CSS v4 마이그레이션 체크리스트: v3→v4 변경점과 @import 전환 가이드

반응형

왜 지금 v4로 옮겨야 할까요

Tailwind CSS v4는 설정과 빌드 방식이 크게 달라져 v3 프로젝트를 그대로 유지하면 스타일 깨짐, 빌드 오류, 퍼포먼스 저하가 발생할 수 있습니다. 특히 @tailwind 지시자와 PostCSS 기반 구성에서 @import 중심의 새 흐름으로 전환되는 점이 핵심 변화입니다.

실무에서는 디자인 토큰과 플러그인 동작이 바뀌면 공통 컴포넌트가 domino처럼 영향을 받습니다. 배포 전에 체크리스트로 위험 구간을 빠르게 점검하면 롤백 없이 안정적으로 옮길 수 있습니다.

이 글은 “무엇이 바뀌었는지 → 어디를 먼저 확인할지 → @import로 어떻게 전환할지” 순서로 안내합니다. 초보자도 따라할 수 있도록 예시와 최소 단계로 정리해 시간을 아끼도록 돕습니다.

v3의 @tailwind에서 v4의 @import로: 개념 전환 한눈에

v3는 PostCSS 플러그인과 tailwind.config.js를 통해 @tailwind base; @tailwind components; @tailwind utilities; 순서로 스타일을 주입했습니다. v4는 CSS 자체의 @import와 레이어 개념을 중심으로 “필요한 것만 가져오는” 구성으로 바뀌어, 빌드 체인이 가벼워지고 의존 경로가 명확해집니다.

사례로, 기존에 theme 확장과 플러그인 의존이 많은 대시보드 프로젝트에서는 레이어 오염이 잦았습니다. v4에서는 tokens.css 같은 파일에 색·간격 값을 선언하고, 컴포넌트 단에서 필요한 유틸리티만 import해 격리도를 높이는 방식이 유지보수에 유리합니다.

또한 v3에서는 글로벌 CSS 한곳에 지시자를 몰아넣었다면, v4는 페이지·컴포넌트 단위로 import를 분리해 코드 스플리팅에 도움이 됩니다. 초기 로드와 라우트 전환 시 불필요한 유틸리티가 줄어들어 번들 크기와 FOUC 위험을 함께 낮출 수 있습니다.

정리하면, 전환의 핵심은 빌드 도구 교체가 아니라 “레이어를 나누고 가져오기 방식으로 관리 범위를 축소”하는 사고 전환입니다. 적용 순서는 다음처럼 작게 쪼개는 편이 안전합니다.

- 글로벌 지시자 파일을 기능별 CSS로 분리
- 디자인 토큰을 별도 파일로 추출
- 페이지/컴포넌트에서 필요한 레이어만 @import
- 플러그인 의존 구간은 대체 유틸리티 또는 로컬 CSS로 단계적 치환

v4 전환 핵심: 파일 단위 @import로 재구성

업데이트 순서는 백업 → 패키지(tailwind, autoprefixer 등) 업데이트 → 빌드 스크립트 점검입니다. 글로벌 @tailwind 지시자는 제거하고, 파일 단위 @import 재구성으로 전환하세요.

디자인 토큰을 분리해 tokens.css에 색상·간격·폰트를 모읍니다. 이렇게 하면 레이어 충돌과 재정의 비용이 줄어듭니다.

컴포넌트·페이지 CSS에서는 필요한 레이어만 선택적으로 불러옵니다. 전역 유틸리티 주입을 줄이면 번들 크기와 FOUC 완화에 도움이 됩니다.

아래는 v3 전역 지시자를 v4의 파일 분리로 옮기는 예시입니다.

/* src/styles/tokens.css */
:root {
  --color-primary: #2563eb;
  --space-2: 0.5rem;
  --radius-md: 0.5rem;
}

/* src/styles/base.css */
@import "./tokens.css";
@import "tailwindcss/base";

/* src/styles/components/button.css";
@import "tailwindcss/components";

.button {
  @apply px-4 py-2 rounded-md text-white;
  background: var(--color-primary);
}

/* src/styles/utilities.css */
@import "tailwindcss/utilities";

전역에는 base와 tokens만 두고, components는 컴포넌트별로 분리합니다. 라우트 엔트리에서 필요한 CSS만 import해 코드 스플리팅을 유도하세요.

마이그레이션 체크리스트
- theme 확장값을 tokens.css로 이관했는지
- @apply가 토큰 변수와 충돌하지 않는지
- 플러그인 레이어 위치(components/utilities)를 명시했는지
- Vite/Webpack CSS import와 트리 셰이킹 흐름이 맞는지
- 페이지 단위 CSS 중복 import가 없는지

@import 전환 시 흔한 함정과 안전 기준

v4로 갈 때 가장 잦은 실수는 v3의 @tailwind를 남긴 채 @import를 추가하는 것입니다. 두 방식을 섞으면 레이어가 이중 주입되어 우선순위 충돌과 번들 비대화가 납니다.

tokens.css를 따로 만들어도 컴포넌트 CSS에 import를 빼먹기 쉽습니다. 토큰이 전역처럼 보여도 코드 스플리팅을 한다면 각 파일에서 명시적으로 가져와야 안전합니다.

플러그인은 v3 전용 PostCSS 동작이 달라질 수 있으니, 대체 유틸리티나 순수 CSS로 치환 대상을 먼저 목록화하고 단계적으로 교체하세요.

선택 기준 요약
- 전역(base/reset)만 공용 파일, 나머지는 페이지·컴포넌트 단위 import
- 토큰은 :root, 다크·테마는 .theme-dark 등으로 스코프 분리
- 사용 빈도 낮은 유틸리티는 on-demand, 공통 패턴은 소형 컴포넌트 CSS로 캡슐화

점검 절차
1) 글로벌 CSS에서 @tailwind 제거
2) tokens.css 분리 후 base.css에서 1회 import
3) 컴포넌트.css는 필요한 레이어만 선택 import(예: utilities)
4) 빌드 로그로 중복 규칙·미사용 CSS 확인

아래 예시는 레이어 중복을 막고 토큰 주입을 보장하는 최소 구성입니다.

/* src/styles/base.css */
@import "./tokens.css";
@import "tailwindcss/base.css";

/* src/components/card.css */
@import "tailwindcss/utilities.css";

.card { border-radius: var(--radius-md); padding: var(--space-2); }

base는 토큰+base, 컴포넌트는 utilities로 분리해 로드 순서를 명확히 하고 불필요한 규칙을 줄입니다.

지금 할 일: 체크리스트로 마이그레이션 마무리

가장 중요한 요지는 v3의 전역 지시자를 걷어내고, 파일 단위 @import로 재구성하는 것입니다. 토큰은 분리하고, 컴포넌트·페이지에서 필요한 레이어만 가져오세요.

바로 실행할 체크리스트
- 패키지 업데이트: tailwind v4, autoprefixer, 빌드 도구 버전 정리
- 글로벌 CSS에서 @tailwind 제거, base/reset만 공용 파일로 유지
- tokens.css 생성 후 :root와 테마 스코프 분리(.theme-dark 등)
- 각 컴포넌트/페이지 CSS에 필요한 @import 명시
- v3 전용 플러그인 목록화 → 대체 유틸리티 또는 순수 CSS로 단계 교체
- 라우트별 번들 확인: 중복 주입, FOUC, 누락 스타일 검증

적용 확인 방법
- 샘플 페이지 2~3개를 고르고 라우팅 전환 시 스타일 깨짐 여부를 점검합니다.
- 빌드 로그에 중복 레이어 경고, 불필요한 CSS 용량 증가가 없는지 확인합니다.

작게 시작해도 충분합니다. 공통 버튼·폼 같은 핵심 컴포넌트부터 전환하고, 영향 범위를 보며 나머지를 묶음으로 진행하세요.

라우터별 @import 배치 요령(Next/Vite/CRA)

프레임워크마다 CSS 로딩 지점이 달라 v4의 @import가 흔들릴 수 있습니다. FOUC와 중복 주입을 막으려면 로딩 계층을 분리하세요.

Next.js(App Router)는 layout.tsx에 글로벌 리셋·토큰을 두고, 페이지/컴포넌트는 내부에서만 필요한 CSS를 가져옵니다. 서버 컴포넌트엔 전역, 클라이언트 컴포넌트엔 지역 CSS만 import해 범위를 나눕니다.

Vite와 CRA는 index.(t|j)tsx에 base/reset·tokens.css만 넣고, 각 라우트에서 유틸리티 묶음을 개별 import합니다. 라우팅별 코드 스플리팅을 고려해 공용과 개별 레이어를 섞지 않는 편이 안전합니다.

“전역은 최소, 라우트는 선택” 원칙 예시입니다.

/* src/styles/base.css */
@import "./tokens.css";
@import "tailwindcss/base";

/* src/pages/dashboard.css */
@import "tailwindcss/components";
@import "tailwindcss/utilities";

base.css는 레이아웃에서 한 번만, 라우트 CSS는 해당 페이지에서만 로드해 초기 번들 부풀림을 줄입니다.

빠른 점검
- 전역(base/tokens)은 루트 레이아웃·엔트리에서 1회 로드
- 페이지/컴포넌트 CSS에 utilities 중복 import 여부 확인
- 전환 시 깜빡임이면 전역·지역 레이어 혼재 여부 우선 점검

반응형