Repository navigation
[전수조사/B] Tailwind className: 보존형 동작과 v4 추종 #687
Copy link
Copy link
Open
Labels
bugSomething isn't workingSomething isn't workingenhancementNew feature or requestNew feature or request
Description
devup 컴포넌트(Box 등)의 className에 있는 Tailwind class를 빌드 타임에 devup CSS로 바꾸는 기능입니다(기본 켜짐). 알아보지 못한 토큰을 지우고, 지원하지 않는 variant를 무조건 적용하는 문제가 있습니다. 확인 예: <Box className="card hidden"> → card 삭제, data-active:p-4 → 항상 적용.
전체 계획과 결정 사항은 추적 이슈(#682)에 있습니다. 조사 기준 커밋: 77daad74 (현재 main d0b84255).
결정에 따른 작업
- (필수) 보존형: 알아보지 못한 토큰과 variant는 원문 그대로 둠(절대 삭제·무조건 적용 금지)
- (권장) Tailwind v4를 따라감(최신). 플러그인 class(
prose등)만 제외, 런타임에 조립되는 class 이름은 원리상 불가 - (권장) breakpoint는 devup 기준(
devup.jsontheme.breakpoints로 변경 가능, 문서화) - (권장)
dark:는 devup theme을 따름(devup은 기본으로 prefers-color-scheme를 읽고data-theme으로 전환) - (권장) devup.json theme 값 사용(
bg-primary,shadow-card등)과 Tailwind 원래 방식(CSS@theme/@utility/@custom-variant, 기본 팔레트)을 모두 지원 - (권장) Tailwind 이름과 같은 class는 Tailwind 의미로 변환된다는 규칙을 문서화
- (권장) v4 conformance 테스트(TW-18)
발견 항목
심각도: P0 = 흔한 사용에서 조용히 틀리거나 크래시, P1 = 흔한 패턴이 명시적 에러로 막히거나 드물게 조용히 틀림, P2 = 드문 경우·도구/문서 불일치, P3 = 있으면 좋음.
필수 (6)
- TW-01 (P0, ?) Mixed
classNameextraction deletes or rewrites unknown, custom, and plugin classes — Tailwind를 쓰지 않아도 발생:<Box className="card hidden">→card삭제- 근거:
trigger-static.tsxtransformsp-4 custom prose unknown-classto only the generated padding class.wrong-partial-replacement.tsxtransforms the untouched branchmy-p-4-classintomy-padding-0-1rem--255-class.prop_modify_utils.rs:47-96rebuildsclassNamefrom generated styles once any Tailwind-looking token triggers extraction, andprop_modify_utils.rs:98-270per… - 수정 방향: Parse into whitespace-delimited class tokens, return a per-token
{consumed, replacement}result, preserve unconsumed tokens exactly, and never use substring replacement for class names.
- 근거:
- TW-02 (P0, ?) Unsupported variants are discarded and their utilities become unconditional
- 근거:
wrong-variants.tsxemits unconditional padding/margin for[&>*]:p-4,data-active:p-4,aria-checked:m-4,has-[img]:p-4,not-hover:m-4,in-focus:mt-4,nth-3:mb-4,*:px-4,:py-4,max-md:p-4,min-[700px]:m-4,@sm:p-4,supports-[display:grid]:p-4, andstarting:p-4.tailwind.rs:59-108splits prefixes but unknown variants do not invalidate the candidate… - 수정 방향: Make variant parsing typed and exhaustive; if any prefix is unknown or malformed, reject conversion for the whole token and preserve it.
- 근거:
- TW-04 (P0, ?) Multi-declaration utilities are truncated to one declaration
- 근거:
wrong-multideclaration.tsx:size-6remains uncompiled;rounded-t-lgemits onlyborder-top-left-radius;truncateonlytext-overflow:ellipsis;sr-onlyonlyposition:absolute;not-sr-onlyonlyposition:static;text-smonlyfont-size. Related combined syntaxtext-sm/6is unsupported. - 수정 방향: Return a vector/structured rule expansion per candidate and encode multi-property utilities explicitly.
- 근거:
- TW-06 (P0, ?) Transform utilities overwrite each other and arbitrary negatives lose their sign
- 근거:
utilities-filter-animation-transform.tsxemits separate whole-transformdeclarations for translate/rotate/scale/skew.wrong-arbitrary.tsxcompiles-translate-x-[13px]to positivetransform:translateX(13px). Tailwind v4 uses composable transform properties/variables: translate, rotate, [sc… - 수정 방향: Model v4 individual properties/composition exactly and carry numeric sign through typed parsing.
- 근거:
- TW-10 (P0, ?) Arbitrary-value parsing corrupts complex values and omits v4 arbitrary properties/variables
- 근거:
wrong-arbitrary.tsxcompilesgrid-cols-[200px_1fr]to invalidrepeat(200px 1fr,minmax(0%,1fr));content-['hello\_world']is dropped;[mask-type:luminance],bg-(--my-color), andtext-(length:--my-size)disappear when mixed withp-4. See using arbitrary values and [handling whitespace](htt… - 수정 방향: Implement a tokenizer/parser for Tailwind candidate syntax before utility-specific lowering; fail closed on parse errors.
- 근거:
- TW-13 (P0, ?) Several implemented variants emit non-equivalent selectors or media behavior
- 근거:
wrong-variants.tsxcompileshover:focus:p-4to.class:hover:focus .class, requiring a descendant rather than styling the element itself. Existing probes show hover lacks Tailwind v4's hover-capable media guard; group/peer output does not use Tailwind's.group/.peermarker semantics;dark:is fixed toprefers-color-schemerather than the configurable variant. Refer… - 수정 방향: Model variants structurally, compose inside-out using
&, and compare generated selectors against Tailwind v4 goldens.
- 근거:
권장 (11)
- TW-03 (P0, ?) Default responsive breakpoints are not Tailwind v4 breakpoints
- 근거: Probes emit
sm:under@media(min-width:480px),md:at 768px,lg:at 992px,xl:at 1280px, and2xl:at 1536px.tailwind.rs:114-133maps variants to Devup responsive indices. Tailwind defaults are 640/768/1024/1280/1536: responsive design. - 수정 방향: Emit explicit Tailwind media queries from Tailwind breakpoint values; add configurable theme breakpoints rather than translating names to Devup indices.
- 근거: Probes emit
- TW-05 (P0, ?)
space-*anddivide-*do not target children- 근거: Broad probe output compiled
space-x-4to parentcolumn-gapanddivide-x-2to parentborder-inline-width; the isolated probe leaves them unchanged depending on trigger recognition, demonstrating inconsistent paths. Tailwind requires child combinators, exclusions, and reverse variables: space between, [d… - 수정 방향: Implement these as structured selector expansions; do not approximate with
gapor parent border properties.
- 근거: Broad probe output compiled
- TW-08 (P0, MISMATCH) Colors are a hard-coded pre-v4 palette and ignore Tailwind theme customization
- 근거:
bg-red-500emits#EF4444andbg-blue-500emits#3B82F6; palette constants are hard-coded intailwind.rs:2141-2201. Tailwind v4 colors use theme CSS variables and OKLCH values: colors, theme. - 수정 방향: Consume an authoritative/configured Tailwind theme artifact or preserve CSS-variable references; version the compatibility contract explicitly.
- 근거:
- TW-07 (P1, ?) Filter and backdrop-filter utilities overwrite instead of compose
- 근거:
utilities-filter-animation-transform.tsxemits eachblur-*,brightness-*,contrast-*, etc. as a completefilter, and each backdrop utility as completebackdrop-filter. Tailwind composes filter functions: filter, backdrop filter. - 수정 방향: Reproduce Tailwind's compositional custom-property/function model or emit a merged rule for the complete candidate set.
- 근거:
- TW-09 (P1, MISMATCH) Gradient syntax and stop composition are not Tailwind v4-compatible
- 근거:
utilities-background-border-effects.tsxaccepts legacybg-gradient-to-*; v4bg-linear-*is unsupported.from-*,via-*, andto-*are lowered independently instead of participating in Tailwind's gradient variable composition. See background image and [gradient color stops](https://tailwindcss.com/docs/gradient-color-sto… - 수정 방향: Replace the legacy gradient table with v4 candidate parsing and exact variable/declaration expansions.
- 근거:
- TW-11 (P1, MISMATCH) Important and opacity modifiers are unsupported
- 근거:
wrong-important-opacity.tsxgenerates no CSS forp-4!,!p-4,bg-red-500/50,bg-red-500/[71.37%], orbg-red-500/(--alpha). Tailwind v4 documents trailing important syntax in the upgrade guide and alpha modifiers in colors. - 수정 방향: Parse modifiers before utility dispatch and apply them to the complete expanded declaration set.
- 근거:
- TW-12 (P1, MISMATCH) Animations reference keyframes that are never emitted; transition coverage is stale
- 근거:
animate-spinemits ananimationdeclaration but the generated sheet contains no@keyframes spin; the same applies to other built-ins. Transition utilities use fixed legacy property lists. Tailwind contracts: animation, transition property. - 수정 방향: Track rule dependencies (keyframes/properties) and emit each required global rule once; update transition definitions to v4.
- 근거:
- TW-14 (P1, MISMATCH) Major valid v4 utility families are absent or only nominally recognized
- 근거: Probes and
tailwind.rs:337-415/utility dispatch show missing or severely incomplete support for container utilities and queries, border spacing, caption side/table layout, masks, forced-color-adjust, field sizing, color scheme, appearance, will-change, scroll snap/margin/padding, isolation/object/logical variants, full decoration/list/content handling, colored shadows, modern… - 수정 방향: Publish a versioned support manifest generated from tested candidate cases; use one registry for recognition and expansion; default to preservation for unsupported candidates.
- 근거: Probes and
- TW-15 (P1, ?) Extraction misses common static tokens inside helper calls, arrays, and identifiers
- 근거:
trigger-expressions.tsxleavesclsx('p-4'), array expressions, and referenced constants unextracted while handling direct literals/templates/conditionals. Tailwind's detector works over complete static tokens in source text: detecting classes. - 수정 방향: Add safe constant folding for arrays/objects/helper allowlists and/or a source-token collection phase; never execute user code.
- 근거:
- TW-17 (P1, ?) Plain DOM and non-Devup component class names are outside the extractor with no compatibility contract
- 근거:
trigger-static.tsxleaves a plain<div className="p-4 bg-red-500" />unchanged while compiling the same string on<Box>. The landing app does not document TailwindclassNameextraction; benchmark apps are the only visible integration examples. - 수정 방향: Publish trigger/opt-in/pipeline documentation with supported component/expression boundaries and coexistence guidance.
- 근거:
- TW-18 (P1, TEST) Existing tests are implementation snapshots, not Tailwind v4 conformance tests
- 근거:
tailwind.rs:2203-2816has many unit cases, but they assert local parser outputs and legacy assumptions; observed wrong outputs (legacy colors/gradients, single declarations, selector approximations) are therefore accepted. No differential fixture against Tailwind v4 was found. - 수정 방향: Generate a representative v4 CSS corpus with official Tailwind, normalize it, compare extractor output, and add browser tests for cascade/composition cases.
- 근거:
선택 (1)
- TW-16 (P2, MISMATCH) Conflict resolution with Devup props is deterministic but property-dependent and undocumented
- 근거:
ordering.tsx: both class orders produce the same globally sorted CSS winners;p={12}beatsclassName="p-4"regardless JSX order, while Tailwindbg-red-500beats Devupbg="green"becausebackground-colorfollowsbackgroundin the generated sheet. Two identical extraction runs ofcorrectness-composition.tsxwere byte-identical. - 수정 방향: Document canonical ordering and mixed-API precedence; consider detecting conflicts and providing one explicit precedence control.
- 근거:
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingenhancementNew feature or requestNew feature or request
Activity
test: list the Tailwind docs page and cover the spacing scale of a un…
merge: main into feat/tailwind-v4-complete
test: cover parenthesized cn arguments, nested --value parentheses an…
chore: merge main into Tailwind class fixes
chore: merge updated Tailwind class fixes into v4 theme
chore: merge updated Tailwind theme into v4 utilities
fix(extractor): compile Tailwind classes one by one with v4 variants …
Merge updated #739 into feat/tailwind-v4-complete
Merge main 76b1a15 into feat/tailwind-v4-complete