Skip to content

fix(extractor): resolve compiled names by lexical binding - #750

Open
owjs3901 wants to merge 12 commits into
mainfrom
fix/scoped-compiled-names
Open

owjs3901 wants to merge 12 commits into
mainfrom
fix/scoped-compiled-names

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Refs #695 (JSX-03 및 minified import 이름 충돌). #742 위에 쌓은 브랜치입니다. #742, #737 및 #730까지의 기반 스택이 먼저 병합되어야 합니다. PR의 base는 요청대로 main입니다.

요약

컴파일 전용 API를 지역 변수의 이름이 아니라 Oxc가 해석한 바인딩(SymbolId)으로 구분합니다. minified 라이브러리의 import { css as a }와 다른 함수의 지역 a가 충돌하여 잘못된 Cannot compose 오류가 발생하던 문제와, 매개변수 Box를 가져온 Devup 컴포넌트로 오인하던 JSX-03을 수정합니다.

동작

  • css, styled, keyframes, globalCss, Devup 컴포넌트, JSX 팩토리, namespace/default/CJS import와 alias를 실제 참조 바인딩으로 확인합니다.
  • 매개변수, const, let, var, 함수, catch 바인딩, 클래스 및 중첩 블록의 동일한 이름은 원래 JavaScript/JSX로 남습니다.
  • StyleX API와 스타일 결과, Emotion Global/ClassNames 콜백, css prop 대상, 숫자 단위 변환 및 상수/변경 분석도 바인딩을 확인합니다.
  • StyleX의 중첩 firstThatWorks/include/types.*와 ClassNames/theme 함수의 theme 읽기도 가져온 API 및 실제 매개변수 심볼을 확인합니다.
  • 배럴의 지역 export/alias 연결 역시 심볼로 확인하며, import보다 앞에 적힌 export를 따라가지 못하던 관련 버그도 수정합니다.
  • 상수 인라인 단계의 semantic scoping을 본 방문자와 공유하고, 최종 남은 컴파일 바인딩 검사도 원래 심볼을 사용합니다. 다시 방문하는 AST 복사본은 참조 ID를 유지하거나 원래 source span의 바인딩으로 복구합니다.
  • 컴파일 import가 없는 파일은 semantic 분석을 건너뜁니다. 런타임 스타일링이나 새 의존성은 추가하지 않습니다.
  • JSX/CSS 변수 lowering이 참조 ID를 잃기 전에 잘못된 컴파일 바인딩의 값 읽기를 검사하며, 쉼표로 연결한 CJS 구조분해와 alias 선언도 순서대로 등록합니다.
  • 중첩 JSX 팩토리의 컴포넌트 인자만 올바른 컴파일 문맥으로 제외합니다. .attrs() 안의 중첩 컴파일 호출은 원래 바인딩이 남아 있을 때 처리하고, 잘못된 값 읽기는 복사 전에 거부합니다.

실제 WASM 프로브에서 다음 입력은 수정 전 minified-call.tsx:4:10: Cannot compose getValue() 오류가 났습니다.

import { css as a } from '@devup-ui/react'
export const real = a({ color: 'red' })
export function minified(a, getValue) {
  return a(getValue())
}

수정 후 실제 출력:

import "@devup-ui/react/devup-ui.css";
export const real = "color-0-red--255";
export function minified(a, getValue) {
  return a(getValue());
}
// CSS: .color-0-red--255{color:red}

function render(Box) { return <Box color="pink" /> }도 <div>로 바뀌지 않고 그대로 남습니다. 지역 호출을 빈 문자열이나 인자로 바꾸던 조용한 오컴파일도 함께 막습니다.

새로 생기는 오류

새 오류 종류는 없습니다. 기존 컴파일 전용 값의 런타임 읽기 및 정적으로 알 수 없는 스타일 오류는 유지하되, 실제 컴파일 바인딩을 읽는 참조에만 적용합니다. 동일한 이름의 지역 변수 때문에 발생하던 잘못된 오류는 사라집니다.

  • <Box p={css}>, className={css}, style={{ color: css }} 등에서 가져온 컴파일 함수 자체를 런타임 값으로 읽으면 기존 오류가 lowering 전에 확실히 발생합니다. 동일한 이름의 지역 값은 허용됩니다.
  • 실제 stylex.create()/defineVars() 안에서 지역 매개변수 firstThatWorks/include/types를 호출한 결과가 정적으로 알려지지 않으면 해당 API의 기존 정적 값/알려진 키 오류를 보고합니다. 이름만 보고 지역 호출을 StyleX helper로 대체하지 않습니다.

남는 한계

빌드에서 알 수 없는 스타일을 런타임 스타일링으로 전환하지 않습니다. 기존 CSS 변수/빌드 오류 계약과 외부 클래스에 대한 CSS cascade 합성 규칙은 그대로입니다.

검증

  • cargo fmt --all, Rust 1.99 workspace/all-targets clippy, cargo test --workspace 통과
  • WASM 및 전체 패키지 재빌드 통과
  • Bun 테스트 통과, 커버리지 100%; lint는 기존 경고 2개 외 오류 없음
  • Rust extractor 1,651개 테스트 통과; Bun 로컬 5,504개 및 최종 CI 5,512개 통과, 0개 실패
  • 실제 WASM 공개 API의 기존 9개, 독립 리뷰 counterexample/control 12개, 중첩 팩토리/attrs/namespace 문맥 9개, 총 30개 통과
  • apps/landing/src의 TS/TSX 138개 파일: 동일 프로세스에서 20회 워밍업 후 100회 순서를 번갈아 측정. 다른 로컬 검증 명령을 함께 실행하지 않은 최종 비교는 전체 추출 중앙값 **25.55 ms → 24.50 ms (-4.09%)**였습니다. 부하가 있던 비교에서는 -1.64%~+2.49%로 변동했고 차이는 전체 1 ms 미만이므로, 확정적인 속도 향상이 아니라 눈에 띄는 성능 회귀가 없다는 근거로 봅니다.
  • Windows 로컬 CI-width tarpaulin은 99.62%이며, 기존 파일에도 미계측 행이 있습니다. Linux CI의 100% 강제 게이트 및 landing/Next E2E 결과는 아래에 기록합니다.
  • 최종 head: 29812f376f62b74071080aec2f35efb9f0424d0f
  • Linux CI 37157363187 전체 success: publish의 Rust 커버리지 100% 강제 게이트, Bun 테스트, landing E2E, landing-next-e2e, vinext-rsc-css-e2e, benchmark 모두 통과
  • Linux tarpaulin: 12,342/12,342행, 100.00%. Bun 최종 CI: 5,512 pass / 0 fail, 커버리지 100%
  • 첫 CI의 Rust 99.98%는 ClassNames 앞 공백 및 숫자가 있는 비함수 자식에 대한 prepass 분기 2개 때문이었습니다. 해당 양성/음성 fixture만 추가한 후 100%를 확인했으며, 커버리지 제외나 경고 억제는 추가하지 않았습니다.

2026-10-08 main 11790bef를 병합하여 업데이트했습니다. 충돌 없이 갱신된 부모 PR의 변경과 main의 변경을 모두 보존했습니다.

2026-10-17 부모 갱신: 확정 main a6ecc125를 포함한 최신 #742 d2328d1c를 병합했습니다. 충돌한 extract_style_from_styled.rs, import_alias_visit.rs, lib.rs, visit.rs는 #750의 semantic SymbolId/Bindings/Kinds를 유지하면서 상위 StyledContext/JSX/slot 예약·bounded capture·조건 spread 우선순위·forwardRef/attrs/ref/target/D1/identity, fallback/kebab/Emotion API/quoted·type import, class arguments/정확한 signed numeric ClassNames/class text, #737의 원본 호출 범위/source-map/namespace 진단을 모두 보존했습니다. 원래 type-import assertion과 비-JSX 문자열 fallback 배열 guard가 각각 실제 실패한 뒤 code만 조정해 같은 assertion으로 통과했습니다. semantic pass의 저비용 선별 조건을 숫자 또는 배열 syntax로 확장하되 실제 symbol 검증/eligible guard는 그대로이며, runtime 값 import가 남을 때의 inline type와 type만 남을 때의 별도 import type를 모두 보존했습니다. 원래 fixture/assertion 수정 및 새 snapshot 후보/수용 0개, #736 별도 기능은 가져오지 않았습니다.

검증: DEFAULT Rust stack/CARGO_BUILD_JOBS=2/전체 트리 6GiB(빌드·테스트), 12GiB(hook)로 Rust 정상 workspace 4,705개/실패 0개, scope 101개/scoping 19개/barrel+pipeline 99개/guard 345개, fmt/Rust1.99 Clippy, fresh WASM/root, lint, Bun 5,939개/실패 0개/커버리지 100%, 실제 WASM/React SSR 64개(alias 40+상위 20+scope 4)를 확인했습니다. source gate Oracle APPROVE/HIGH 후 전체 hook 412.453초/peak4.118GiB가 통과했고, 정확한 두 부모 74afb760/d2328d1c의 새 merge 7f98689c를 정상 push했습니다. 마지막 fresh WASM/root 및 scope 실제 재검증도 통과했습니다. Windows Rust 97.70%(21126/21624)는 Linux 100% 증명이 아니므로 새 head CI를 별도 기록합니다. 기존 lint 경고 9개 외 오류 없음, LSP 응답 불가를 clean이라 주장하지 않습니다.

새로 생기는 오류: 이번 부모 갱신으로 새 오류 정책/의존성/runtime helper/opaque fallback 없음. 새 private QA의 ClassNames 선언문 body는 기존 at-once 계약에 맞는 직접 반환식으로, 생성 atom의 위치 가정은 기존 opaque-first composition 규칙에 맞는 정확한 numeric token 순서/중복/zero 및 red atom 1회 적용 관찰로 바로잡았을 뿐 원래 test/production은 바꾸지 않았습니다. 상위 #737/#742의 CI는 확정 main에서도 별도 재현한 leading JSX pragma 소실 때문에 local-barrel Bun 회귀 1개가 실패한 상태이며, W67 별도 branch fix/keep-jsx-pragmas가 수정합니다(PR 번호 추후). 이를 outage/green acceptance로 분류하거나 체인 fixture/tsconfig/workflow workaround를 추가하지 않고 coordinator 지시대로 갱신을 계속합니다.

실제 WASM/공개 API 검증 출력:

[
  {
    "name": "component-shadow",
    "source": "import {Box} from '@devup-ui/react';const Nested=(Box)=><Box p={3}/>;const Target=({p})=><aside data-p={p}/>;const App=()=> <><Box p={2}>compiled</Box>{Nested(Target)}</>;",
    "code": "import \"@devup-ui/react/devup-ui.css\";\nconst Nested = (Box) => <Box p={3} />;\nconst Target = ({ p }) => <aside data-p={p} />;\nconst App = () => <><div className=\"a\">compiled</div>{Nested(Target)}</>;\n",
    "map": "{\"version\":3,\"names\":[],\"sources\":[\"C:\\\\Users\\\\devfive3901\\\\AppData\\\\Local\\\\Temp\\\\opencode\\\\workers\\\\w60-chain-updates\\\\W60f-750-component-shadow.tsx\"],\"sourcesContent\":[\"import {Box} from '@devup-ui/react';const Nested=(Box)=><Box p={3}/>;const Target=({p})=><aside data-p={p}/>;const App=()=> <><Box p={2}>compiled</Box>{Nested(Target)}</>;\"],\"mappings\":\";AAAoC,MAAM,UAAQ,QAAM,CAAC,IAAI,GAAG;AAAK,MAAM,UAAQ,EAAC,QAAK,CAAC,MAAM,QAAQ;AAAK,MAAM,YAAS,EAAE,mBAAW,QAAQ,OAAO,OAAO,MAAM,EAAE\"}",
    "html": "<div class=\"a\">compiled</div><aside data-p=\"3\"></aside>",
    "css": "/*! devup-ui v1.0.83, | Apache License 2.0 | https://devup-ui.com */.a{padding:8px}"
  },
  {
    "name": "css-shadow",
    "source": "import {css} from '@devup-ui/react';const cls=css({color:'red'});function scoped(css){return css({color:'blue'});}const App=()=> <div className={cls} data-user={scoped(x=>'authored:'+x.color)}>child</div>;",
    "code": "import \"@devup-ui/react/devup-ui.css\";\nconst cls = \"a\";\nfunction scoped(css) {\n\treturn css({ color: \"blue\" });\n}\nconst App = () => <div className={cls} data-user={scoped((x) => \"authored:\" + x.color)}>child</div>;\n",
    "map": "{\"version\":3,\"names\":[],\"sources\":[\"C:\\\\Users\\\\devfive3901\\\\AppData\\\\Local\\\\Temp\\\\opencode\\\\workers\\\\w60-chain-updates\\\\W60f-750-css-shadow.tsx\"],\"sourcesContent\":[\"import {css} from '@devup-ui/react';const cls=css({color:'red'});function scoped(css){return css({color:'blue'});}const App=()=> <div className={cls} data-user={scoped(x=>'authored:'+x.color)}>child</div>;\"],\"mappings\":\";AAAoC,MAAM;AAAuB,SAAS,OAAO,KAAI;CAAC,OAAO,IAAI,EAAC,OAAM,OAAM,CAAC;AAAE;AAAC,MAAM,YAAS,CAAC,IAAI,WAAW,KAAK,WAAW,QAAO,MAAG,cAAY,EAAE,KAAK,GAAG,KAAK,EAAE\"}",
    "html": "<div class=\"a\" data-user=\"authored:blue\">child</div>",
    "css": "/*! devup-ui v1.0.83, | Apache License 2.0 | https://devup-ui.com */.a{color:red}"
  },
  {
    "name": "class-names-signed-and-shadow",
    "source": "import {ClassNames} from '@emotion/react';const App=()=> <ClassNames>{({css,cx})=><div className={cx(css({color:'red'}),-1,+2,-0)} data-user={((cx)=>cx('token'))(x=>'local:'+x)}>child</div>}</ClassNames>;",
    "code": "import \"@devup-ui/react/devup-ui.css\";\nconst App = () => <div className={\"-1 2 a\"} data-user={((cx) => cx(\"token\"))((x) => \"local:\" + x)}>child</div>;\n",
    "map": "{\"version\":3,\"names\":[],\"sources\":[\"C:\\\\Users\\\\devfive3901\\\\AppData\\\\Local\\\\Temp\\\\opencode\\\\workers\\\\w60-chain-updates\\\\W60f-750-class-names-signed-and-shadow.tsx\"],\"sourcesContent\":[\"import {ClassNames} from '@emotion/react';const App=()=> <ClassNames>{({css,cx})=><div className={cx(css({color:'red'}),-1,+2,-0)} data-user={((cx)=>cx('token'))(x=>'local:'+x)}>child</div>}</ClassNames>;\"],\"mappings\":\";AAA0C,MAAM,YAAkC,CAAC,IAAI,qBAA4C,aAAa,OAAK,GAAG,OAAO,EAAC,AAAC,EAAC,MAAG,WAAS,CAAC,GAAG,KAAK,EAAE\"}",
    "html": "<div class=\"-1 2 a\" data-user=\"local:token\">child</div>",
    "css": "/*! devup-ui v1.0.83, | Apache License 2.0 | https://devup-ui.com */.a{color:red}"
  },
  {
    "name": "styled-shadow",
    "source": "import {styled} from '@devup-ui/react';const Real=styled.section({color:'red'});function pick(styled){return styled('user');}const User=pick(tag=>props=><aside data-tag={tag}>{props.children}</aside>);const App=()=> <><Real>compiled</Real><User>ordinary</User></>;",
    "code": "import \"@devup-ui/react/devup-ui.css\";\nimport { forwardRef as __devupForwardRef } from \"react\";\nconst Real = __devupForwardRef((__devupRefProps, __devupRef) => (({ style, className, as: DevupAs = \"section\", forwardedAs, ...rest }) => <DevupAs {...(({ \"theme\": __devupOmit0, ...__devupDom }) => __devupDom)(rest)} as={forwardedAs} className={[\"a\", className].filter(Boolean).join(\" \")} style={style} />)({\n\t...__devupRefProps,\n\tref: __devupRef\n}));\nfunction pick(styled) {\n\treturn styled(\"user\");\n}\nconst User = pick((tag) => (props) => <aside data-tag={tag}>{props.children}</aside>);\nconst App = () => <><Real>compiled</Real><User>ordinary</User></>;\n",
    "map": "{\"version\":3,\"names\":[\"tyled} fro\",\"devup-ui/react';c\"],\"sources\":[\"C:\\\\Users\\\\devfive3901\\\\AppData\\\\Local\\\\Temp\\\\opencode\\\\workers\\\\w60-chain-updates\\\\W60f-750-styled-shadow.tsx\"],\"sourcesContent\":[\"import {styled} from '@devup-ui/react';const Real=styled.section({color:'red'});function pick(styled){return styled('user');}const User=pick(tag=>props=><aside data-tag={tag}>{props.children}</aside>);const App=()=> <><Real>compiled</Real><User>ordinary</User></>;\"],\"mappings\":\";AAAA,SAASA,cAAcC,yBAAyB;AAAT,MAAM;;;;AAAmC,SAAS,KAAK,QAAO;CAAC,OAAO,OAAO,MAAM;AAAE;AAAC,MAAM,OAAK,MAAK,SAAK,UAAO,CAAC,MAAM,UAAU,MAAM,MAAM,SAAS,EAAE,MAAM;AAAE,MAAM,YAAS,EAAE,CAAC,KAAK,QAAQ,EAAE,KAAK,CAAC,KAAK,QAAQ,EAAE,KAAK\"}",
    "html": "<section class=\"a\">compiled</section><aside data-tag=\"user\">ordinary</aside>",
    "css": "/*! devup-ui v1.0.83, | Apache License 2.0 | https://devup-ui.com */.a{color:red}"
  }
]

2026-10-17 최신 head 7f98689c CI run 38946644133은 실패이며 outage/green acceptance로 분류하지 않습니다. publish job 117127339134에서 Linux Rust 100.00% coverage, 15088/15088 lines covered 및 일반 검증은 통과했고, Regression test (bun-plugin preload race)의 동일한 local-barrel consumer/react/jsx-dev-runtime 오류 1개만 실패했습니다. 다른 benchmark/landing-next-e2e/vinext-rsc-css-e2e job은 모두 통과했습니다. 이 frozen-main pragma 버그는 W67 별도 fix/keep-jsx-pragmas가 수정 중이며, coordinator 지시대로 체인 fixture/source/assertion/workflow workaround 없이 기록하고 갱신을 계속합니다. 새 head의 최종 green CI는 아직 미완료입니다.

2026-10-17 위 실패의 main JSX pragma 버그 수정은 별도 PR #784입니다. 실제 frozen-main 재현으로 분리된 오류이며 outage/green으로 바꾸지 않습니다. #784를 이 체인에 직접 병합하지 않고, 사용자가 main에 병합한 뒤 coordinator가 지시하는 main 갱신으로만 반영합니다.

W60p 최신 부모·확정 main 재통합

최신 head는 588b1fff5ef15a3b82e7f879be9d87b6674c6039입니다. 먼저 현재 #742 0ab122f5를 참 병합한 1742bb59096cb3d540c427eb7abd1b10563330b1을 만들고, 그 위에 확정 main 770aaac5977f1eae9771516b60868daed842e63c를 참 병합했습니다. 두 merge 모두 정확한 두 부모를 확인했고, 각각 검증한 전체 트리에서 정상 hook을 한 번씩 통과했습니다(634.393초/590.583초, peak4.503/4.499GiB). 중간 head는 push하지 않았으며 최종 head만 정상 push했습니다.

최종 main 병합 트리의 로컬 검증은 DEFAULT Rust stack·stable·CARGO_BUILD_JOBS=2·CI unset·6GiB 빌드/테스트·12GiB hook으로 fmt/Clippy, Rust 6,545 pass / 0 fail, fresh WASM/root/lint, Bun 6,649 pass / 0 fail / coverage100%, 실제 공개 WASM·React·문맥 115개와 결정론적 재추출12개 및 출력 바이트 감사를 통과했습니다. 부모 병합과 최종 main 병합 모두 foreground Oracle APPROVE/HIGH입니다. 기존 snapshot은 바꾸지 않았습니다. main 통합 중 발견한 imported Emotion12px→48px 회귀는 숫자 리터럴 전용 shortcut을 수정해 원래12px assertion 그대로 통과시켰습니다. LSP는 서비스 timeout이므로 clean이라고 주장하지 않습니다.

새 head의 Linux Rust100% 강제 gate와 전체 CI는 아직 대기/미확정입니다. push 직후 run 목록에는 과거 7f98689c run만 있어 그것을 새 head의 결과로 재사용하지 않았습니다. 새 head와 일치하는 run을 확인한 뒤 실제 결과를 추가합니다.

W60p 조건 평가·런타임 코드·새 오류

이 갱신은 main에도 남아 있던 StyleX 조건의 중복·누락 평가를 수정합니다. 조건은 인자 순서대로 정확히 한 번 평가하며, 이후 키가 모두 덮어쓰거나 두 분기가 같거나 비어 있어도 원래 getter·예외·변경 효과를 지우지 않습니다. 기존 본문의 과거 새 오류 없음 설명은 이 갱신의 아래 NEW located error에 적용되지 않습니다.

새 런타임 코드는 캡처가 필요한 실행 스코프의 초기화 없는 let _sN, ...;와 조건당 한 번의 _sN = !!(<원본 조건>)뿐입니다. 대입은 원래 호출 위치에 남고, 이후 키 선택은 그 논리값을 읽습니다. 기존 concise arrow를 같은 arrow의 block/return 본문으로 바꿀 수 있으나 함수 수는 늘지 않습니다. 새 callable/IIFE/helper/import/배열/전역 scratch/레지스트리/런타임 클래스 병합은 없습니다. 직접 eval 가드는 빌드 시 검사만 추가하며 허용되는 출력에는 코드가 추가되지 않습니다.

실제 공개 WASM 출력의 대표 다중 키 예시는 다음과 같습니다. 원본 조건 ++n === 1을 두 번 넣던 255바이트 출력이 아래 276바이트로 바뀝니다(UTF-8 원문 +21바이트, minify/gzip 수치 아님). 새 선언과 대입은 각각 한 번입니다.

import "@devup-ui/react/devup-ui.css";
import * as sx from "@stylexjs/stylex";
const s = { "base": "a b" };
export function probe() {
	let _s0;
	let n = 0;
	const out = (_s0 = !!(++n === 1), { className: `${_s0 ? "b" : ""} ${_s0 ? "a" : ""}` });
	return [n, out.className];
}

모든 키가 나중에 덮어써지는 예시는 새 저장소 없이 const out = (++n === 1, { className: "d c" });로 원래 효과를 보존합니다. 실제 전체 출력은 **229→242바이트(+13)**이며 새 let/대입/callable은 없습니다. 저장이 불필요한 단일 키·같은 분기·빈 값·덮어쓴 조건은 기본값과 필드에서도 계속 지원합니다. 정적 클래스·CSS 변수 및 기존 React/props 전달 코드의 계약은 바꾸지 않습니다.

NEW located error

안전한 실행별 저장소를 만들 수 없는 조건은 조용히 오컴파일하거나 런타임 helper로 바꾸지 않고 원래 조건 위치에서 거부합니다. 기본값(구조분해·arrow 포함), instance/static/private/auto-accessor 필드 및 저장소가 없는 expression-only 문맥에 적용됩니다. 정확한 메시지 템플릿은 다음과 같습니다.

StyleX condition capture is not supported in {context}; move the value into a variable in a statement body

예를 들어 아래 입력의 마지막 줄이 function f(out=sx.props(flag() && s.base)){}이면 capture-context.js:3:25: StyleX condition capture is not supported in a parameter default; move the value into a variable in a statement body입니다. class C { out=sx.props(flag() && s.base); }이면 같은 파일 :3:24에서 context가 a class field initializer인 오류입니다.

import * as sx from '@stylexjs/stylex';
const s=sx.create({base:{color:'red',backgroundColor:'blue'}});
function f(out=sx.props(flag() && s.base)){}

또한 캡처용 바인딩을 직접 eval 또는 중첩 eval 클로저가 볼 수 있는 문장 스코프는 다음 새 오류로 거부합니다. 형제 스코프·간접 eval·바깥에서 정의된 eval 클로저와 안쪽 캡처 블록·저장 불필요 조건은 계속 허용됩니다.

capture-eval.js:3:31: StyleX condition capture is not supported in a statement body whose bindings are visible to direct eval; move the value into a variable in a scope not visible to direct eval

위의 2줄 import/정의 뒤 마지막 줄이 function probe(){try{sx.props(eval('_s0') && s.base);return 'accepted';}catch(error){return error.name;}}인 실제 native/public-WASM 회귀에서 확인했습니다. 문자열 안의 이름을 예약하는 우회가 아니라 원래 semantic scope ancestry로 가시성을 판단합니다.

중복 ClassNames 표현이던 scope/class_names.rs를 제거하고 하나의 ClassNamesParams로 통합했습니다. #729의 중첩 active binding stack·최외곽 한 번의 준비·Rc scoping 재사용과 상위 marker/imported-styled/barrel/alias 동작은 유지합니다. dependency·경고 억제·coverage 제외·스택 확장은 추가하지 않았습니다.

추출 성능

동일한 212개 실제 landing/components/react 소스를 pre-capture WASM과 수정 WASM으로 같은 프로세스에서 비교했습니다. 각 세트는 엔진당 warmup 3회 후 순서를 교대로 바꾼 25회씩이며 모든 표본을 보존했습니다. 오류 0, CSS 27,493바이트, 전체 생성 코드/CSS digest가 양쪽에서 일치합니다. 최종 dependency-first lowering을 main 통합 전에 비교한 세트 C 중앙값은 **47.877→50.253 ms (1.050x, +2.377 ms)**입니다. 이전 중간 캡처 구현의 세트 A는61.076→54.801 ms(0.897x), B는48.631→48.887 ms(1.005x)였고 공유 호스트의 변동 범위가 겹칩니다. 측정한 +4.96% 차이를 숨기거나 확정적 속도 향상을 주장하지 않으며, 최종 빌드 성능은 새 head의 Linux benchmark 결과와 별도로 확인합니다. 불필요 저장소 제거 후 8/16/32/64 조건 출력은 470/706/1186/2146바이트로, 이전598/967/1719/3223바이트보다 줄었습니다(64조건에서1077바이트 감소). branch-product 확장은 만들지 않습니다.

W60p 새 head 588b1fff5ef15a3b82e7f879be9d87b6674c6039의 CI run 39463256355는 failure입니다. benchmark(직접 turbo1.060x, 정적 turbo1.084x 포함), wasm-size, React18, Next E2E, vinext RSC, release-compat, webpack theme job은 모두 성공했지만 publish의 Rust coverage는 99.98%,16,817/16,821행으로100% gate를 통과하지 못했습니다. Rust 테스트 자체는 모두 통과했으며, 미계측4행은 CI-width 기준 stylex_no_storage_tests.rs:42, visit.rs:1540-1541,1564입니다. threshold·workflow·baseline을 바꾸거나 snapshot/assertion을 약화하지 않고 해당 경로를 검증하는 테스트를 보강합니다. publish의 Bun/후속 E2E는 이 실패로 아직 실행되지 않았으므로 최종 CI green/Bun100%라고 주장하지 않습니다.

W60p 커버리지 보강 head 0807cc8a3093adbb612f4a704c3403fae1252a8f를 588b1fff 위에 정상 push했습니다. alternate-only 키의 실제 CSS winner/효과를 양쪽 API·두 조건값·상속 유무로 검증하는8개와 기존 fixture helper의 unknown-frame panic 음성1개를 추가했습니다. 불가능한 (None,None)는 key와 원래 class/side를 함께 보관해 표현할 수 없게 했고, 원본 dead test/false placeholder/order를 유지하는 조기 guard로 계측 위치를 명료하게 했습니다. 기존 assertion·snapshot·threshold·workflow·baseline은 바꾸지 않았고 새 runtime/error policy도 없습니다. 로컬 Rust 6,554/0, fresh WASM/root/lint 및 Bun 6,649/0·100%, 실제 공개115개+결정론적12개·출력 감사를 통과했고 foreground Oracle APPROVE 후 정상 hook1회가 848.912초·peak4.606GiB로 통과했습니다. lowering274행으로 승인 범위 이내입니다. 이전 run39463256355의99.98%를100%로 둔갑시키지 않으며 이 새 head의 Linux100%·전체CI는 새 run에서 확인 중입니다.

W60p 최종 GREEN: head 0807cc8a3093adbb612f4a704c3403fae1252a8f, CI run 39476073858 attempt1 success입니다. Linux Rust coverage 100.00%,16,821/16,821행, Bun 6,649 pass / 0 fail·coverage100% 및 publish/benchmark/wasm-size/landing-next-e2e/React18/vinext-rsc-css-e2e/release-compat/webpack-extends-theme 검증이 모두 통과했습니다(release/deploy는 PR 조건으로 skip). 직접/정적 turbo 비율은 1.066x/1.053x로 통과했으며 benchmark 재실행·baseline/tolerance/workflow 변경은 없었습니다. 이전 run39463256355의99.98% 실패는 경로 검증9개와 불가능 상태 제거/동일 dead-test guard 보존으로 해결했고 assertion·snapshot·coverage 제외·스택 확장은 추가하지 않았습니다. 앞서 명시한 NEW capture-context 오류와 let/대입/시퀀스 출력·바이트 증가는 그대로이며, 확정 main770aaac5가 포함된 두 참 merge 1742bb59,588b1fff와 coverage follow-up의 정상 hook은 각 검증 트리에서 한 번씩 통과했습니다.

2026-10-21 MAIN SETTLED 78d7c2b 충돌 해소

요약

MAIN SETTLED 78d7c2b2를 #750에 실제 두 부모 merge로 반영했습니다. libs/extractor/src/imported_constants.rs의 세 충돌과 libs/extractor/src/visit.rs의 한 충돌을 해결하여 #750의 SymbolId 기반 lexical binding과 #798의 constant css tagged-template metadata/located diagnostics를 함께 보존했습니다.

동작

  • imported constants는 이름이 아니라 semantic binding으로 style API를 인식하며, named/namespace css tagged template의 객체 interpolation을 기존 composition에 연결합니다.
  • #798의 strict lexical recognition, metadata-preserving clone, located error와 #750의 imported style/StyleX/scoping/px 동작을 함께 유지합니다.
  • merge 중 발견한 오래된 helper signature 충돌은 기존 Bindings::reads_module predicate를 사용하도록 맞췄고, assertion을 약화하거나 runtime helper/dependency를 추가하지 않았습니다.
  • 테스트 fixture의 worker 경로 표기를 중립적인 경로로 바꿔 shipped-name 규칙을 만족시켰습니다.

새로 생기는 오류

새 오류 정책은 없습니다. 기존 build-time 오류 위치와 메시지, 동적으로 알 수 없는 값의 located refusal, zero-runtime 계약을 유지합니다.

남는 한계

빌드가 알 수 없는 스타일 값을 runtime styling으로 전환하지 않습니다. 외부 class와 runtime-only composition은 기존 CSS cascade 계약을 따릅니다.

검증

  • fresh bun install, WASM build, root build, cargo fmt --all, strict workspace/all-target/all-feature Clippy, Rust workspace tests 통과
  • Rust workspace 테스트 통과; focused factory/metadata suite 222/222, focused constant css-tag suite 129/129
  • bun run test: 6,654 pass / 0 fail, All files functions 100.00 / lines 100.00; lint 0 errors와 기존 warnings 20개
  • shipped-name guard 통과, 실제 WASM probe에서 card = "a" 및 .a:hover{color:blue} 확인
  • 정확한 merge tree에서 정상 hook 1회 통과, merge commit 6300750 (parents 0807cc8 + 78d7c2b)
  • 최신 head CI 39583548515 SUCCESS: Linux Rust 16,987/16,987 lines (100.00%), Bun All files functions/lines 100.00/100.00, publish/benchmark/wasm-size/React18/Next/vinext/release-compat/webpack jobs 모두 성공

owjs3901 and others added 6 commits October 4, 2026 06:06
Refs #695

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

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

Refs #695

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

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

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

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

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

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

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

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

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

  • A project module re-exporting Devup UI (export { Box, css } from '@devup-ui/react', export * from '@devup-ui/react', export { styled as s }, export * as Devup, a default export of an import, chains of barrels and the compat entry) now works: a file importing Box or css from it compiles exactly as if it imported from the package, following the barrel through the resolver (relative paths, tsconfig paths, package exports), and hasDevupUI sees such a file. Members read from a namespace or default import of the package (Devup['css'], const { css } = Devup, Devup.css as a value) compile where the build can follow them, Devup.x for a name the package compiles being read like the named import. New build errors, located at the use: what a barrel re-exports but the build cannot read (an unresolvable export * or module, a namespace of modules re-exporting the package) is an error where its name is used instead of a runtime crash, and a namespace member read by a key the build cannot know (Devup[key]), written, or destructured in a form it cannot follow (a rest, a computed key, a default value, a nested pattern, an exported declaration, or members mixed with ones that stay at runtime) is an error that names the members to read. A namespace passed on whole (Object.keys(Devup), spyOn(Devup, 'css'), export default Devup) is left as it is
  • css(a, b) composing classes whose styles the build knows (a const bound to css() in the file, or a css() result another module exports with a rule object every value of which is known) merges their styles: a later part's declaration replaces an earlier one's for the same property, selector, breakpoint and layer, also under conditions (css(base, cond && danger)) and for ||/?? parts, where the classes used to be joined and the stylesheet order picked the winner. vanilla-extract style([a, b]) passes each composed style as its own argument, so the later one wins, and a style composed again later (style([a, b, a])) is kept. Classes the build does not know (strings, props, CSS Modules) are kept as they are
  • styled(Base) extending a styled component the file binds to a const renders Base's tag directly with Base's styles composed under its own, so the extension's declarations replace Base's for the same property, selector, breakpoint and layer instead of losing to them by stylesheet order; Base's attrs apply before the extension's. attrs merge as styled-components merges them: className is joined with the caller's, style is merged and other props replace earlier ones. On an element, a className or style spread after the explicit prop now wins, as React merges props in the order they are written
  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion and styled-components component selectors now compile at build time: a styled component the file defines that another style selects (${Child} { ... } in CSS text, [Child] or [&:hover ${Child}] as a rule key) gets a short marker class, which only such components get, and the selector reads it as .marker; a component extending it, or an element inlining it for its css prop, keeps the marker. Selectors written without & now nest under the component as stylis nests them (ul { ... } is & ul, a selector list nests each selector, :hover applies to the component itself) instead of becoming global rules, and rule-object keys starting with ., #, [, *, >, + or ~ are read as nested selectors instead of properties
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • 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.
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read
  • Resolve compiled styling APIs and components by their lexical binding so shadowed local names, including minified library identifiers, remain ordinary JavaScript and JSX. No new build errors; existing diagnostics now apply only to the compiled binding they describe.
  • Styled components the build generates are wrapped in React's forwardRef, so a ref passed to them reaches the element they render on React 18 as well as React 19; the file imports forwardRef from react when it defines one
  • Styled components no longer pass every prop to the tag they render: $ props, theme and the props their style functions or attrs read are kept away from a tag unless it takes them as attributes, and shouldForwardProp (Emotion options or styled-components withConfig) is evaluated at build time. A shouldForwardProp the build cannot evaluate is a build error naming the file, line and code, with the forms it accepts. An element using a styled component the file defines drops props the component neither reads nor passes on; spread props are passed as written
  • Styled components render what their as prop names, defaulting to the tag or component they were defined with, and pass forwardedAs on as as, as styled-components and Emotion do; as used to reach the rendered tag as an attribute. Component.withComponent(target) on a styled component the file binds to a const builds a component rendering the same styles and attrs as target (a tag name or a component JSX can name), where it used to call a method the generated function does not have and throw
  • 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

@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
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read

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

Patch

  • Auto-update: depends on '@devup-ui/react' 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

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@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
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/react@1.0.44 → 1.0.45 - packages/react/package.json

Patch

  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/reset-css@1.0.31 → 1.0.32 - packages/reset-css/package.json

Patch

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

@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
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

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

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@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
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@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/extractor/src/barrel.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/gate.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values.rs 100.00% <100.00%> (ø)
...bs/extractor/src/ci_factory_alias_support_tests.rs 100.00% <100.00%> (ø)
libs/extractor/src/css_prop.rs 100.00% <100.00%> (ø)
...tractor/src/extractor/extract_style_from_styled.rs 100.00% <100.00%> (ø)
...tractor/src/extractor/extract_style_from_stylex.rs 100.00% <100.00%> (ø)
libs/extractor/src/import_alias_scoping_tests.rs 100.00% <100.00%> (ø)
libs/extractor/src/import_alias_visit.rs 100.00% <100.00%> (ø)
... and 17 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.

No conflicted files; retain PR changes and merge updated parent #742, which contains main 11790be.
owjs3901 added a commit that referenced this pull request Oct 8, 2026
No conflicted files; retain PR changes and merge updated parent #750, which contains main 11790be.
Refs #682 #695 #688 #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 added a commit that referenced this pull request Oct 16, 2026
Refs #682 #695 #688 #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 added a commit that referenced this pull request Oct 17, 2026
Refs #682 #695 #688 #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 4 commits October 21, 2026 01:03
Refs #682 #695 #688 #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #682 #695 #688 #689

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #682 #695 #688 #689

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

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

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 added a commit that referenced this pull request Oct 21, 2026
…ixes

The alias style-order fixture from #798 used styleOrder 0, which the 1 to 254 contract of this PR rejects as a located build error; it now uses the valid order 2 with unchanged assertions.

Refs #684

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 pushed a commit that referenced this pull request Oct 22, 2026
Refs #685, #694

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.

2 participants