Skip to content

feat(extractor): compile containers, masks, 3D transforms, functional @utility and class helpers - #749

Open
owjs3901 wants to merge 16 commits into
mainfrom
feat/tailwind-v4-complete
Open

owjs3901 wants to merge 16 commits into
mainfrom
feat/tailwind-v4-complete

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Refs #687 (B, 권장 항목 3부: W8에서 보고한 Tailwind v4 빈틈 닫기). #739(feat/tailwind-v4-utilities) 위에 쌓은 PR이며 #705 → #734 → #739 → 이 PR 순서로 병합되어야 합니다. base가 main이라 병합 전에는 앞선 PR의 커밋도 함께 보입니다.

요약

  • 감시: Rsbuild는 Tailwind CSS 파일(과 상대 경로로 import한 CSS)이 바뀌면 다시 읽고 모든 모듈을 다시 컴파일합니다(rspack watchRun에서 mtime을 비교하고, 각 모듈에 addDependency). Bun은 파일을 fs.watch로 지켜 다시 읽습니다(bun-plugin은 런타임 플러그인이라 자체 재빌드가 없으므로 다음에 모듈을 로드할 때 새 정의로 컴파일됩니다).
  • 유틸리티(모두 v4 소스 기준):
    • 컨테이너 쿼리: @sm:, @max-md:, @min-[400px]:, @[30rem]:, 이름 있는 @sm/main:(너비는 --container-*, 프로젝트가 바꾸거나 initial로 비울 수 있음). @container, @container-normal, @container-size, @container/main.
    • 마스크: mask-none, mask-[...], mask-size-*, mask-position-*, composite, mode, type, size, position, repeat, clip, origin.
    • text-shadow-*(2xs~lg, none, 색, inherit, initial)와 inset-shadow-*(2xs, xs, sm, none, 색)는 shadow-*와 같은 합성 구조입니다.
    • font-variant-numeric: ordinal, slashed-zero, lining-nums, oldstyle-nums, proportional-nums, tabular-nums, diagonal-fractions, stacked-fractions가 --tw-* 변수로 합성되고 normal-nums.
    • 3D: rotate-x|y|z-*, translate-z-*, scale-z-*(음수 포함), translate-3d, scale-3d, transform-3d, transform-flat, transform-cpu|gpu, backface-*, perspective-*(테마 --perspective-*와 임의 값), perspective-origin-*.
    • contain-*(contain-size|inline-size|layout|paint|style은 변수로 합성), outline-hidden(@media (forced-colors: active)의 outline: 2px solid transparent; outline-offset: 2px까지).
    • outline-hidden을 위해 한 class가 규칙 안의 at-rule에 선언을 따로 가질 수 있게 했습니다(TailwindClass.nested).
  • 정의: 함수형 @utility name-*(--value(integer, number, percentage, 'literal', --ns-*, [length|color|number|url|…]), --modifier(...)), @utility 안의 @apply(다른 @utility를 거쳐도 펼침, 순환·variant·자식 대상 유틸리티는 그 @utility 전체가 원문으로 남음), 임의 값 안의 theme(--name)(프로젝트 변수, 색, 간격; 읽을 수 없으면 그 class는 원문). @plugin/@config는 JavaScript를 실행해야 출력이 나오므로 읽지 않고, 그 class(prose 등)는 원문 그대로 둡니다(문서에 적음).
  • 헬퍼:
    • cn(...)/twMerge(...): 모든 인자가 문자열·${} 없는 템플릿·그들의 배열일 때만 tailwind-merge처럼 합칩니다(뒤의 class가 같은 속성·조건·중요도를 모두 덮으면 앞의 class를 지움, px-4와 p-2는 둘 다 유지). 조건식 등 다른 인자가 있으면 건드리지 않습니다(런타임 결과여서, twMerge가 원문을 받아야 하므로).
    • cva(base, { variants, compoundVariants }): base, variant 옵션, compound class/className의 class를 그 자리에서 컴파일합니다(cva는 이어붙이기만 하므로 정확). Devup UI를 import하는 파일에서만 동작합니다.
    • 같은 파일의 const에 묶인 문자열(const base = 'p-4 card', ${} 없는 템플릿)을 className이 읽는 자리에서 펼쳐 컴파일합니다. 심볼 분석(oxc semantic)으로 읽으므로 가려진(shadowed) 이름이나 let은 건드리지 않습니다.
  • 문서: docs/migration/tailwind의 읽는 위치, 정의, 원문으로 남는 목록을 위 내용에 맞게 갱신했습니다.

동작

probe.ts(devup.json 색 primary와 아래 Tailwind CSS)로 확인한 실제 출력:

@theme { --color-brand: oklch(60% 0.2 250); }
@utility tab-* { tab-size: --value(integer); }
@utility btn { @apply px-4 py-2 rounded; }
const base = 'p-4 card'
const button = cva('rounded-lg', { variants: { size: { sm: 'text-sm' } }, compoundVariants: [{ size: 'sm', class: 'm-2' }] })
<Box className={base} />
<Box className={cn('p-4 m-2 card', 'p-2', 'hover:p-1')} />
<Box className={cn('p-4', on && 'p-2')} />
<Box className={button({ size })} />
<Box className="@container/main @md:p-4 @max-sm:hidden" />
<Box className="text-shadow-md inset-shadow-sm tabular-nums contain-layout outline-hidden mask-cover" />
<Box className="perspective-near transform-3d rotate-x-45 translate-z-4 backface-hidden" />
<Box className="tab-4 btn bg-[theme(--color-brand)]" />
<Box className="mask-linear-50 prose" />
const button = cva("a", { variants: { size: { sm: "b c" } }, compoundVariants: [{ size: "sm", class: "d" }] });
<div className="e card" />                                   // const base
<div className="d card f g" />                               // cn: p-4 → 지워지고 m-2, card, p-2, hover:p-1
<div className={cn("p-4", on && "p-2") || ""} />             // 조건이 있어 그대로
<div className={button({ size }) || ""} />                   // cva 안의 class는 컴파일
<div className="h i j k" />   <div className="a-d ae af ag ah" />
<div className="mask-linear-50 prose" />                     // 그라디언트 마스크와 prose는 그대로
@container(width>=28rem){.j{padding:1rem}}  @container(width<24rem){.k{display:none}}  .h{container-type:inline-size}  .i{container-name:main}
.l{text-shadow:0 1px 1px var(--tw-text-shadow-color,rgb(0 0 0 / .1)),0 1px 2px var(--tw-text-shadow-color,rgb(0 0 0 / .1)),0 2px 4px var(--tw-text-shadow-color,rgb(0 0 0 / .1))}
.m{--tw-inset-shadow:inset 0 2px 4px var(--tw-inset-shadow-color,rgb(0 0 0 / .05))}
.o{--tw-numeric-spacing:tabular-nums}  .p{font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}
.q{--tw-contain-layout:layout}  .r{contain:var(--tw-contain-size,) var(--tw-contain-layout,) var(--tw-contain-paint,) var(--tw-contain-style,)}
.z{--tw-rotate-x:rotateX(45deg)}  .aa{--tw-translate-z:1rem}  .x{perspective:300px}  .y{transform-style:preserve-3d}  .ac{backface-visibility:hidden}
.ab{translate:var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)}
@media(forced-colors:active){.u{outline:2px solid transparent}.v{outline-offset:2px}}
.a-d{tab-size:4}  .ah{background-color:oklch(60% .2 250)}  .ae{padding-inline:1rem}  .af{padding-block:.5rem}  .ag{border-radius:.25rem}

새로 생기는 오류

없음.

남는 한계

  • 컴파일하지 않고 원문으로 남기는 것: container(breakpoint마다 폭이 다른 규칙이라 한 class로 표현할 수 없음), 그라디언트 마스크(mask-linear-*, mask-radial-*, mask-conic-*, mask-t|r|b|l|x|y-from|to-*: 여러 변수와 mask-composite: intersect에 걸친 합성이라 이번에는 정확히 재현하지 않음), @plugin/@config로 만들어지는 class, @utility 안의 중첩 규칙, --spacing()/--alpha() 등을 쓰는 함수형 @utility.
  • cn은 twMerge(clsx(...))로 읽습니다(import를 확인할 수 없음). 다른 동작을 하는 cn이면 이름을 바꿔야 한다고 문서에 적었습니다.
  • cva는 Devup UI를 import하지 않는 파일에서는 처리되지 않습니다(파일 전체가 처리 대상이 아님). 다른 파일에서 import한 상수와 let/매개변수의 class 문자열은 읽지 않습니다.
  • Bun은 파일이 바뀌면 정의를 다시 읽지만, 이미 컴파일된 모듈은 다음 로드 때 새로 컴파일됩니다.

검증

  • cargo fmt --all, cargo +1.99 clippy --workspace --all-targets -- -D warnings, cargo test --workspace 통과. WASM 재빌드 후 bun run build, bun test(5496 pass, 0 fail, 커버리지 100%), bun lint(기존 경고 2개 외 추가 없음).
  • 테스트: 군마다 v4 소스(utilities.ts, variants.ts, theme.css)의 CSS와 비교(컨테이너 쿼리 11개 형태와 읽지 않는 형태, 컨테이너 유틸리티, 마스크, text/inset shadow, numeric/contain 합성, 3D, perspective, outline-hidden의 중첩 at-rule, 변수에 의한 컨테이너 폭), 정의(함수형 @utility의 값 종류와 modifier, @apply 순환·variant, theme() 해석/미해석), 헬퍼(cn/twMerge 병합 규칙과 건드리지 않는 경우, cva의 모든 위치와 스프레드, 가려진 const와 let), 플러그인(Rsbuild watchRun·addDependency, Bun 감시자의 재읽기·오류·중복 감시 방지).
  • 추가 발견(범위 밖): 없음.

2026-10-08 업데이트: main 11790bef를 merge commit으로 병합했습니다; 충돌 파일: libs/extractor/src/tailwind.rs, packages/bun-plugin/src/plugin.ts, packages/rsbuild-plugin/src/tests/checkout-isolation.test.ts, packages/rsbuild-plugin/src/tests/plugin.test.ts, packages/rsbuild-plugin/src/plugin.ts; Tailwind 중첩 선언과 Bun SourceLoader/CSS 출력 및 Tailwind 감시 기능을 모두 유지하고, Rsbuild 파일 입출력·감시 import와 테스트 setup을 결합했으며 스타일시트 테스트가 두 번째 콜백을 선택하도록 수정했습니다.

owjs3901 and others added 7 commits October 1, 2026 18:23
…and declarations

Classes Tailwind does not define stay in the className as written, a class with a variant the compiler does not understand is left unchanged instead of applying unconditionally, and utilities emit every declaration Tailwind v4 writes: multi-declaration utilities in full, translate/rotate/scale/skew through their own properties so they compose, and arbitrary values read with Tailwind's grammar. Template classNames keep text that runs into an interpolation attached to it.

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…and composed utilities

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…f Tailwind v4

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…it with digits

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…Utility and class helpers

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…d unknown rotate axes

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

@devup-ui/wasm@1.0.83 → 1.0.84 - bindings/devup-ui-wasm/package.json

Patch

  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.
  • Tailwind classes in a className: each class compiles on its own and every class Tailwind does not define (custom, plugin and analytics classes) stays as written, where any recognized class used to rebuild the whole className without them and could rewrite part of another class; a class touching a template interpolation (icon-${name}) is left as written, and template classNames no longer get spaces inserted around interpolations. A class whose variant is not understood stays as written instead of applying unconditionally; variants follow Tailwind v4: stacked variants compose (hover:focus: matches the element itself), hover is guarded by @media (hover: hover), group-/peer- use the group/peer marker classes (and group-hover/name), and data-, aria-, has-, nth-, , **, supports-[…] and [&…]/[@media …] variants compile. Utilities emit all their declarations (size-, rounded-t-, truncate, sr-only, not-sr-only, text-sm with its line height, text-sm/6, leading-), translate/rotate/scale/skew compose through Tailwind's individual properties and registered variables (@Property) with negative values kept negative, and arbitrary values follow Tailwind's grammar: spaces for underscores except in url() and var() names, _ for an underscore, spaces around math operators, type hints, [property:value] and (--variable) shorthands. Words that only share a utility's prefix (select-wrapper, order-summary, cursor-foo) are no longer compiled
  • More of Tailwind CSS v4 compiles: container queries (@sm:, @max-md:, @min-[400px]:, @sm/main:) and @container utilities, mask-* (all but the gradient masks), text-shadow-, inset-shadow-, font-variant-numeric utilities (tabular-nums and the like), 3D transforms (rotate-x/y/z, translate-z, scale-z, translate-3d, scale-3d, transform-3d, backface-, perspective-, perspective-origin-), contain- and outline-hidden (with its forced-colors fallback). The project's Tailwind CSS is read further: functional @Utility with --value() and --modifier(), @apply in @Utility, and theme(--name) in arbitrary values; classes of @plugin entries stay as written. A className now compiles the classes of cn()/twMerge() calls whose arguments are all static (merged as tailwind-merge does, the later class wins), of consts bound to class strings, and of cva() calls (base, variants, compound variants). The Rsbuild plugin reads the Tailwind CSS again and compiles every module again when it changes, and the Bun plugin reads it again. No new build errors
  • Tailwind classes in a className follow Tailwind CSS v4: colors are the v4 default palette (oklch) and the colors and shadows of devup.json theme are usable as Tailwind theme values (bg-primary, text-text, shadow-card, as var(--token)); the opacity modifier (bg-red-500/50, /[71.37%], /(--alpha)) mixes with color-mix as v4 does; a trailing or leading ! makes every declaration important; blur, brightness, contrast, grayscale, hue-rotate, invert, saturate, sepia and their backdrop-* forms compose through Tailwind's custom properties instead of overwriting filter and backdrop-filter; gradients use bg-linear-, bg-conic- and bg-radial-* with from-, via- and to-* composing through the gradient variables (bg-gradient-to-* is not defined by v4 and stays as written); animate-* brings the @Keyframes it names and transition, duration, delay and ease follow v4; space-* and divide-* apply to the children like v4 (:where(& > :not(:last-child))); @Property rules are emitted only for the custom properties a class uses. Anything the build cannot reproduce exactly (drop-shadow-*) stays as written in the className. No new build errors
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/bun-plugin@1.0.22 → 1.0.23 - packages/bun-plugin/package.json

Patch

  • Bun plugin works with Bun.build: DevupUI() (from @devup-ui/bun-plugin/register) serves the generated stylesheet to the bundler's CSS loader once every other module is loaded, so the build emits a CSS output with the styles of the whole bundle instead of an empty module; class names are short there and readable under the runtime (debug option). Files importing the packages Devup UI takes the place of (@emotion/react, @emotion/styled, styled-components, @vanilla-extract/css), @stylexjs/stylex, or a subpath or re-export of these or @devup-ui/react, are compiled instead of skipped
  • More of Tailwind CSS v4 compiles: container queries (@sm:, @max-md:, @min-[400px]:, @sm/main:) and @container utilities, mask-* (all but the gradient masks), text-shadow-, inset-shadow-, font-variant-numeric utilities (tabular-nums and the like), 3D transforms (rotate-x/y/z, translate-z, scale-z, translate-3d, scale-3d, transform-3d, backface-, perspective-, perspective-origin-), contain- and outline-hidden (with its forced-colors fallback). The project's Tailwind CSS is read further: functional @Utility with --value() and --modifier(), @apply in @Utility, and theme(--name) in arbitrary values; classes of @plugin entries stay as written. A className now compiles the classes of cn()/twMerge() calls whose arguments are all static (merged as tailwind-merge does, the later class wins), of consts bound to class strings, and of cva() calls (base, variants, compound variants). The Rsbuild plugin reads the Tailwind CSS again and compiles every module again when it changes, and the Bun plugin reads it again. No new build errors
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/components@0.1.60 → 0.1.61 - packages/components/package.json

Patch

  • Auto-update: depends on '@devup-ui/vite-plugin' via a local workspace dependency

@devup-ui/eslint-plugin@1.0.22 → 1.0.23 - packages/eslint-plugin/package.json

Patch

  • style-order-range only checks styleOrder where the build reads it: a prop of a Devup UI component and a top-level key of a style object passed to css/globalCss/keyframes. A styleOrder key in nested data, in a prop value such as an element passed as a prop, or in a call of a function sharing a name with an Object.prototype member is no longer reported. The array, typography and media rules already skip non-style data, and css-utils-literal-only accepts a css()/keyframes() result held in a const inside a function. No new build errors.

@devup-ui/next-plugin@1.0.90 → 1.0.91 - packages/next-plugin/package.json

Patch

  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/plugin-utils@1.0.17 → 1.0.18 - packages/plugin-utils/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/rsbuild-plugin@1.0.67 → 1.0.68 - packages/rsbuild-plugin/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • More of Tailwind CSS v4 compiles: container queries (@sm:, @max-md:, @min-[400px]:, @sm/main:) and @container utilities, mask-* (all but the gradient masks), text-shadow-, inset-shadow-, font-variant-numeric utilities (tabular-nums and the like), 3D transforms (rotate-x/y/z, translate-z, scale-z, translate-3d, scale-3d, transform-3d, backface-, perspective-, perspective-origin-), contain- and outline-hidden (with its forced-colors fallback). The project's Tailwind CSS is read further: functional @Utility with --value() and --modifier(), @apply in @Utility, and theme(--name) in arbitrary values; classes of @plugin entries stay as written. A className now compiles the classes of cn()/twMerge() calls whose arguments are all static (merged as tailwind-merge does, the later class wins), of consts bound to class strings, and of cva() calls (base, variants, compound variants). The Rsbuild plugin reads the Tailwind CSS again and compiles every module again when it changes, and the Bun plugin reads it again. No new build errors
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/vite-plugin@1.0.73 → 1.0.74 - packages/vite-plugin/package.json

Patch

  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@devup-ui/webpack-plugin@1.0.71 → 1.0.72 - packages/webpack-plugin/package.json

Patch

  • Webpack and Rsbuild builds hold every style in their stylesheets: a stylesheet module is built on its first import, so styles extracted later (the global styles of files webpack or Rsbuild reached late, often outside src) were missing from the output. The files the entries reach under src are now extracted before the build, the shared base on disk is kept current, and when a stylesheet still changed during the build it is compiled once more, writing only the complete result. Rsbuild serves each stylesheet from the current sheet instead of a module-wide string kept only when it grew, which left edits that shortened the CSS and later builds in the same process stale. plugin-utils adds computeReachableFiles
  • Tailwind classes in a className read the Tailwind CSS of the project: the file that imports tailwindcss (the tailwind.css option of devup.json, else a conventional path) gives @theme variables (colors, spacing, shadows, blurs, radii, easings, animations with their @Keyframes, default transitions, breakpoints), @Utility utilities and @custom-variant variants, and the Vite, webpack and Next.js plugins read it again when it or a CSS file it imports changes. Anything that cannot be read exactly, and the classes of namespaces the build does not read, stay as written. More of Tailwind CSS v4 compiles: ring-, inset-ring-, ring-offset-* and drop-shadow-* compose with shadows and filters, borders and outlines draw in --tw-border-style and --tw-outline-style (a border now shows its style), line-clamp, text decoration, border-spacing, logical and scroll spacing, tables, perspective, font-stretch and more; the arguments of clsx(), classnames() and classNames() and [...].join(' ') compile in place. Radii follow v4 (rounded-sm is 0.25rem, rounded-full is calc(infinity * 1px)). No new build errors

@codecov

codecov Bot commented Oct 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
libs/css/src/lib.rs 100.00% <ø> (ø)
libs/css/src/tailwind_definitions.rs 100.00% <100.00%> (ø)
libs/css/src/theme_tokens.rs 100.00% <100.00%> (ø)
libs/extractor/src/lib.rs 100.00% <ø> (ø)
libs/extractor/src/prop_modify_utils.rs 100.00% <100.00%> (ø)
libs/extractor/src/style_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/tailwind.rs 100.00% <ø> (ø)
libs/extractor/src/tailwind_children.rs 100.00% <100.00%> (ø)
libs/extractor/src/tailwind_color.rs 100.00% <100.00%> (ø)
libs/extractor/src/tailwind_custom.rs 100.00% <100.00%> (ø)
... and 15 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

owjs3901 and others added 2 commits October 6, 2026 15:14
Resolve libs/extractor/src/tailwind.rs by preserving the new TailwindClass declaration/condition structure and the removal of the obsolete parser helper, matching the main integration in #749. Keep the Rust 1.99 assertion fixes and regenerate bun.lock workspace metadata for main published versions.

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Merge #705 head 031e8b5, which contains main a935315. Resolve libs/css/src/theme_tokens.rs by retaining the color/shadow token test and the Rust 1.99 typography assertion together, byte-for-byte matching #749; preserve all main integration and published versions.

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Merge #734 head faf23c5, which contains main a935315. No unresolved conflict files remain: lower-stack resolutions flow cleanly through theme_tokens.rs and tailwind.rs. Auto-merged packages/vite-plugin/src/plugin.ts and its plugin.test.ts retain both Tailwind definition watching and main RSC CSS forwarding/restoration, byte-for-byte matching reference merge 753f418 in #749; preserve main published versions.

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 6 commits October 8, 2026 15:18
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
No conflicted files. The exact original #705 head 031e8b5 is already an ancestor; retain its implementation with the ours strategy.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Resolved libs/extractor/src/tailwind.rs by retaining #749's nested declarations alongside #705's per-class v4 compilation and #734/#739 theme and utility integration.

Resolved packages/bun-plugin/src/plugin.ts by retaining #703's SourceLoader/scanner/build stylesheet emission and #749's Tailwind watcher with its returned file list. Resolved packages/rsbuild-plugin/src/plugin.ts by combining #704's synchronous complete stylesheet helpers with #749's stat-based Tailwind watch invalidation.

Resolved packages/rsbuild-plugin/src/__tests__/checkout-isolation.test.ts and plugin.test.ts by retaining #704's onBeforeBuild/rootPath setup alongside all Tailwind watcher tests. After reproducing four failing stylesheet tests, their shared test setup now selects the second Rspack config callback (stylesheet completion), while the first remains the Tailwind watcher. No snapshots or lockfiles were hand-merged, no PR intent was removed, and #734/#739/#749 remain separate PRs.

Refs #687

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant