Skip to content

fix(css): encode values in debug class names, update dependencies - #672

Merged
owjs3901 merged 12 commits into
mainfrom
fix/debug-classname-value-encoding
Sep 24, 2026
Merged

owjs3901 merged 12 commits into
mainfrom
fix/debug-classname-value-encoding

Conversation

@owjs3901

@owjs3901 owjs3901 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

문제

debug 모드(플러그인 debug: true, bun-plugin은 항상)에서 만드는 클래스명에 스타일 값이 그대로 들어간다. selector는 encode_selector로 인코딩하지만 값은 인코딩하지 않았다.

<div class="scale-0-.8-_c_is_…_a_-255 background-0-$text--255 transition-0-all .2s ease-in-out--255">
.background-0-$text--255{background:var(--text)}
.transition-0-all .2s ease-in-out--255{transition:all .2s ease-in-out}
:is([role=group],[data-group]):active .scale-0-.8-_c_is_…_a_-255{scale:.8}

생성된 CSS를 Chromium에 넣어 cssRules로 확인했다 (규칙 9개).

값 브라우저 해석 결과
24px 정상 적용
.8, .5, $text, 50%, calc(100% - 10px), all .2s ease-in-out 잘못된 selector 규칙 전체 drop
#FFF .color-0- 클래스 + #FFF--255 id 파싱되지만 매칭 불가
1px solid #DDD 자손 선택자 파싱되지만 매칭 불가

9개 중 실제로 적용되는 규칙은 width 하나뿐이다.

공백이 들어간 값은 HTML class 속성에서도 여러 토큰으로 쪼개진다(transition-0-all / .2s / ease-in-out--255). 그래서 CSS를 쓸 때 이스케이프(CSS.escape)하는 것만으로는 해결되지 않는다. 이스케이프한 규칙도 파싱은 되지만 매칭되는 클래스가 없다. 클래스명을 만들 때 값을 인코딩해야 한다.

프로덕션(비 debug) 빌드는 base-37 이름(a, b, …)을 쓰므로 영향이 없다.

수정

sheet_to_classname의 debug 분기에서 값도 selector와 같은 encode_selector를 거치게 했다.

let value = encode_selector(&optimized);
  • .8 → _d_8, $text → _dl_text, #FFF → _h_FFF, 50% → 50_pc_, all .2s ease-in-out → all_s__d_2s_s_ease-in-out
  • 영숫자, -, _만 있는 값(24px, red)은 그대로다

테스트

  • libs/css: test_debug_sheet_to_classname_encodes_value 추가 (0.8, $text, #fff, 50%, all .2s ease-in-out)
  • packages/components: 원시 값이 들어간 debug 클래스명을 기대하던 toHaveClass 단언 7곳(Input, Textarea, Select, Stepper)을 인코딩된 이름으로 바꿨다
  • 스냅샷 9개 재생성. 바뀐 209쌍의 줄을 디코딩해 비교하면 기존 스냅샷과 모두 같다. 인코딩 외의 변화는 없다

검증 (Windows, Bun 1.4.2)

  • bun run test (pre-commit): Rust 커버리지 98.19% (9015/9181, +0.00%), bun test 5204 pass / 0 fail, 89 snapshots, 함수·라인 커버리지 100%
  • bun run lint: 통과 (변경과 무관한 기존 경고 1건)
  • 수정한 WASM으로 추출한 debug CSS를 Chromium에 로드: 규칙 9/9 파싱, class 토큰 9개, 모든 규칙이 요소에 매칭(:active는 빼고 검사), background, transition, color, height, opacity 적용 확인 (수정 전: 3/9 파싱, 1개 적용)

릴리스

@devup-ui/wasm Patch changepack을 추가했다. 플러그인들은 workspace:^로 의존하므로 semver 범위 안에서 수정본을 받는다.


의존성 업데이트

bunx @dependency-check-updates/cli -d -u --rm으로 모든 manifest를 최신으로 올리고, bun.lock과 Cargo.lock을 처음부터 다시 만들었다. 그래서 전이 의존성도 호환되는 최신 버전으로 올라갔다.

주요 변경:

  • Rust: oxc 0.147 → 0.151, rstest 0.26 → 0.27, wasm-bindgen 0.2.128, js-sys 0.3.105, wasm-bindgen-test 0.3.78
  • JS: React 19.2 → 19.3, Vite 8.2 → 8.3, vinext beta.8 → beta.12, @vitejs/plugin-rsc 0.5.35, Storybook 10.6, typescript-eslint 8.70, ESLint 10.11, Playwright 1.63, bun-test-env-dom 1.1.0 (happy-dom 20.14), StyleX 0.19.1, @types/node 26.6
  • CI: actions-rust-lang/setup-rust-toolchain v1 → v2

업그레이드 때문에 고친 것

  • oxc 0.151: ParserReturn::panicked가 같은 의미의 fatal_error로 이름이 바뀌어 3곳을 고쳤다.
  • happy-dom 20.14: Button 테스트의 toHaveStyle 단언 5개가 실패했다. 그런데 이 단언들은 원래부터 아무것도 검사하지 않고 있었다. happy-dom 20.11은 style setter에서 var()를 거부해서 기대값이 ''가 되고, 테스트 DOM에는 생성된 CSS가 로드되지 않아 계산된 스타일도 ''이라 항상 통과했다. 20.14가 var()를 파싱하면서 드러났다. 다른 컴포넌트 테스트처럼 해당 선언을 가진 debug 클래스를 toHaveClass로 확인하도록 바꿨다.
  • setup-rust-toolchain v2: 경고 차단이 RUSTFLAGS=-D warnings 대신 CARGO_BUILD_WARNINGS=deny로 바뀌었다. 그래서 bindings/devup-ui-wasm/.cargo/config.toml의 rustflags가 로컬과 똑같이 CI에서도 적용된다. action input은 쓰지 않으므로 워크플로우 수정은 없다.

올리지 못한 것

  • minicov 0.3.8 (0.3.9 있음): wasm-bindgen-test 0.3.78이 =0.3.8로 고정한다. wasm32 커버리지 전용 전이 의존성이라 upstream이 올려야 한다.
  • typescript-eslint 8.70의 peer가 typescript <6.1.0이라 설치 시 TS 7.0.2 경고가 난다. 기존과 같은 상황이고, ESLint는 이미 eslint-typescript6.cjs로 TS 6에서 돌고 있다. upstream이 TS 7을 지원해야 한다.

참고

@devup-ui/react와 @devup-ui/components의 dependencies.react가 ^19.3으로 올라갔다.

검증 (업데이트 후, Windows)

  • bun run lint: 통과
  • bun run test: Rust 커버리지 98.20% (9017/9182, +0.00%), bun test 5204 pass / 0 fail, 커버리지 100%
  • bun-plugin test:regression 5/0, verify:dist 통과
  • 빌드: 전체 패키지, Storybook, landing build(vinext), build:next
  • E2E (win32 기준 스크린샷): vinext 130 passed, Next 130 passed
  • 벤치마크 샘플 빌드: next-stylex-turbo, next-stylex, vinext-devup-ui, next-devup-ui
  • 예제 앱 빌드: next, rsbuild, vite, vite-lib. vite 예제는 첫 빌드에서 rolldown 오류가 한 번 났는데, 이후 5번(클린 빌드 4번 포함)은 재현되지 않았다

owjs3901 and others added 5 commits September 24, 2026 21:15
Debug class names encoded the selector but appended the style value
verbatim. Values such as .8, $text, 50% or calc() made the emitted
selector invalid, so browsers dropped the rule. #FFF turned into an ID
selector, and values with spaces split one class into several class
tokens, so those rules never matched.

Run the value through the same encoder as the selector. Production
builds are unaffected; they use base-37 names.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…lasses

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…lasses

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Regenerated with bun test --update-snapshots; every changed line decodes
back to the previous snapshot, so only value encoding differs.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
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 Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

@devup-ui/wasm@1.0.80 → 1.0.81 - bindings/devup-ui-wasm/package.json

Patch

  • Encode style values in debug class names so values with dots, spaces, $, #, % or parentheses no longer produce invalid CSS selectors

@devup-ui/bun-plugin@1.0.19 → 1.0.20 - packages/bun-plugin/package.json

Patch

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

@devup-ui/components@0.1.57 → 0.1.58 - packages/components/package.json

Patch

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

@devup-ui/eslint-plugin@1.0.20 - packages/eslint-plugin/package.json

Maybe you forgot to write the following files to the latest version

@devup-ui/next-plugin@1.0.87 → 1.0.88 - packages/next-plugin/package.json

Patch

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

@devup-ui/react@1.0.43 - packages/react/package.json

Maybe you forgot to write the following files to the latest version

@devup-ui/rsbuild-plugin@1.0.64 → 1.0.65 - packages/rsbuild-plugin/package.json

Patch

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

@devup-ui/vite-plugin@1.0.70 → 1.0.71 - packages/vite-plugin/package.json

Patch

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

@devup-ui/webpack-plugin@1.0.68 → 1.0.69 - packages/webpack-plugin/package.json

Patch

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

@codecov

codecov Bot commented Sep 24, 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% <100.00%> (ø)
libs/extractor/src/lib.rs 100.00% <100.00%> (ø)
🚀 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 7 commits September 24, 2026 21:45
happy-dom 20.11 rejected var() in style setters, so toHaveStyle compared
an empty expected value against an empty computed style and always
passed. The generated CSS is never loaded into the test DOM, so there is
no computed style to check. happy-dom 20.14 parses var(), which exposed
these assertions.

Assert the debug class that carries each declaration instead, as the
other component tests already do.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bump oxc 0.147 -> 0.151, rstest 0.26 -> 0.27 and the wasm-bindgen
family. oxc 0.151 renames ParserReturn::panicked to fatal_error with the
same meaning. Cargo.lock is regenerated from scratch, so transitive
crates move to their latest compatible versions.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Regenerated from scratch, so transitive packages move to their latest
compatible versions as well.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
v2 denies warnings through CARGO_BUILD_WARNINGS instead of setting
RUSTFLAGS=-D warnings, so the rustflags in
bindings/devup-ui-wasm/.cargo/config.toml now apply in CI the same way
they do locally. No action inputs are used here.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@owjs3901 owjs3901 changed the title fix(css): encode values in debug class names fix(css): encode values in debug class names, update dependencies Sep 24, 2026
@owjs3901
owjs3901 merged commit 398f398 into main Sep 24, 2026
4 checks passed
@owjs3901
owjs3901 deleted the fix/debug-classname-value-encoding branch September 24, 2026 14:34
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