Skip to content

[전수조사/D] 흡수 라이브러리 기능: css prop, 컴포넌트 선택자, @emotion/css, VE·StyleX API #690

Description

@owjs3901

원 라이브러리에서 흔히 쓰는 기능 중 지원되지 않거나 조용히 빠지는 것들입니다.

전체 계획과 결정 사항은 추적 이슈(#682)에 있습니다. 조사 기준 커밋: 77daad74 (현재 main d0b84255).

결정에 따른 작업

  • (필수) Emotion css prop: import/pragma/tsconfig jsxImportSource/컴파일된 @emotion/react/jsx-runtime(include 라이브러리 포함; 감지 비용 측정 결과 MUI 1,312파일 약 2.9 ms). DOM 요소는 항상, 사용자 컴포넌트는 Emotion 신호가 있을 때만 컴파일. 사용자 컴포넌트의 동적 값은 style도 전달해야 함(문서화)
  • (필수) 컴포넌트 선택자: 선택자로 참조된 컴포넌트에만 짧은 marker class
  • (필수) @emotion/css: css/keyframes/injectGlobal/cx/merge. cx는 이슈 A의 정적 합성 사용
  • (필수) alias된 Emotion 파일의 배열 값은 fallback 의미(EMO-15)

발견 항목

심각도: P0 = 흔한 사용에서 조용히 틀리거나 크래시, P1 = 흔한 패턴이 명시적 에러로 막히거나 드물게 조용히 틀림, P2 = 드문 경우·도구/문서 불일치, P3 = 있으면 좋음.

필수 (7)

  • EMO-01 (P0, WRONG) Emotion css prop is never compiled in any source or compiled-JSX form (KNOWN-1)
    • 근거: css-prop-no-import.tsx emits <div css={{ color: 'red' }} /> and no CSS; css-prop-jsx-runtime.ts retains import { jsx } from '@emotion/react/jsx-runtime' and { css: { color:'red' } }; css-prop-css-result.tsx emits const style="a" but retains <div css={style}>
    • 수정 방향: recognize JSX css attributes independent of imports, Emotion jsx/jsxs factory calls and jsx-runtime subpaths; lower accepted values through the normal style extractor, remove css, and merge into className/style with Emotion precedence
  • EMO-03 (P0, WRONG) Nested composition silently drops serialized styles
    • 근거: react-css-nested-compose.tsx turns css({ '&:hover,&:focus': hotpink }) into export const hover = ""; only the unrelated base .a{color:hotpink} remains, with no hover/focus rule or error
    • 수정 방향: resolve known css-result bindings as nested rule fragments, preserving selector context; otherwise emit an explicit build error instead of empty output
  • SX-03 (P0, WRONG) attrs returns the wrong inline-style representation
    • 근거: Dynamic width produces { class: "b", style: { "--a": ... } }.
    • 수정 방향: Serialize dynamic variable declarations for attrs while retaining object form for React-oriented props.
  • VE-04 (P0, WRONG) companion CSS generators silently bypass Devup
    • 근거: recipe(...), defineProperties(...), and createSprinkles(...) remain verbatim while both per-file and whole-sheet Devup CSS contain no recipe/sprinkle rules. Only exact @vanilla-extract/css is aliased (packages/plugin-utils/src/types.ts:96-103); ordinary node_modules are skipped (packages/plugin-utils/src/shared.ts:46-60, packages/vite-plugin/src/plugin.ts:525-554…
    • 수정 방향: Either integrate/alias companion packages and generate their CSS, or detect these imports and issue a build error telling users to disable the Devup alias/use the vanilla-extract plugin.
  • EMO-12 (P1, ERR-gap) Emotion component selectors fail in both template and object forms
    • 근거: styled-selector-template.tsx errors Cannot place Child; styled-selector-object.tsx errors on [Child]
    • 수정 방향: assign a stable marker only to selector-referenced styled components and resolve bindings/computed keys to that marker; emit the marker in parent selector rules
  • EMO-15 (P1, WRONG) CSS fallback arrays are silently reinterpreted as responsive values
    • 근거: object-fallback-values.tsx turns background:['red','linear-gradient(...)'] into .a{background:red} plus @media(min-width:480px){.b{background:linear-gradient(...)}}; Emotion emits two same-rule declarations as browser fallbacks
    • 수정 방향: in Emotion-aliased rule objects, distinguish property-value arrays (fallback declarations) from top-level style arrays; do not route property arrays through Devup responsive semantics
  • EMO-16 (P1, MISMATCH) @emotion/css and create-instance are entirely outside alias handling despite DECIDED support (KNOWN-12)
    • 근거: every emotion-css-*.tsx probe retains imports/calls and emits no extracted CSS; DEFAULT_IMPORT_ALIASES at packages/plugin-utils/src/types.ts:98-103 lacks @emotion/css and its subpath
    • 수정 방향: add explicit @emotion/css mappings for extractable APIs and a deliberate policy/error for stateful low-level APIs; generate matching ambient declarations

권장 (12)

  • EMO-04 (P1, ERR-gap) Global supports only a direct object, rejecting documented static css-result and array forms
    • 근거: react-global-css-result.tsx errors that "a" is not usable; react-global-array.tsx rejects a static array; react-global-theme-function.tsx rejects a function
    • 수정 방향: feed Global through the same composition flattener as css; support exact theme paths as CSS variables and retain explicit errors for genuinely runtime-only functions
  • EMO-13 (P1, ERR-gap) Function object styles are rejected although they are a primary Emotion styled form (KNOWN-7)
    • 근거: styled-function-object.tsx errors on props => ({ color: ... }); styled-theme-object.tsx errors on ({theme}) => ..., while the equivalent template interpolation works via CSS variables
    • 수정 방향: lower property-level exact branches to classes/variables using the same machinery as template functions; explicitly reject object shapes that are unknowable at build time
  • SX-04 (P1, ERR-gap) dynamic contextual values are rejected
    • 근거: A dynamic namespace with color:{default:'red', ':hover':size, '@media (min-width:600px)':size} errors that the object cannot be used at build time.
    • 수정 방향: Recursively decompose contextual objects in dynamic namespaces and bind each dynamic leaf to the generated runtime variable assignment.
  • SX-05 (P1, WRONG) all types.* wrappers lose typed custom-property semantics
    • 근거: Every helper (length, lengthPercentage, color, angle, integer, number, percentage, time, url, image, resolution, transformFunction, transformList) emits only :root{--a:<value>}. Code treats any types.* as a transparent first-argument wrapper (libs/extractor/src/stylex.rs:234-246,585-597).
    • 수정 방향: Carry the helper kind into variable metadata, emit one typed @property, and validate/cast helper-specific values (especially integer).
  • SX-06 (P1, WRONG) explicit global variable names are not preserved
    • 근거: Output is { "--global": "var(--a)" } plus :root{--a:black}, and use via colors['--global'] is separately rejected as non-static.
    • 수정 방향: Detect dashed custom-property keys before identifier allocation; keep --global in both returned reference and emitted root declaration, and resolve computed literal access.
  • SX-07 (P1, WRONG) positionTry output is semantically wrong and cannot be consumed
    • 근거: Declaration probe emits @position-try --a{position-anchor:var(--anchor);...} for positionAnchor:'--anchor'; the documented consumption positionTryFallbacks:fallback errors that fallback is not static.
    • 수정 방향: Preserve dashed identifiers for anchor properties and register positionTry bindings as resolvable static identifiers in create.
  • SX-08 (P1, ERR-gap) viewTransitionClass implements the wrong input shape
    • 근거: {old:{animationDuration:'2s'}, new:{animationDuration:'1s'}} produces two build errors saying nested objects are not static values. The extractor reads one flat declaration object (libs/extractor/src/extractor/extract_style_from_stylex.rs:42-71).
    • 수정 방향: Parse the four documented groups, emit pseudo-element rules, and reject only unsupported nested media queries.
  • SX-09 (P1, ERR-gap) contextual-selector APIs are absent
    • 근거: Dedicated probes for ancestor, descendant, siblingBefore, siblingAfter, and anySibling all error that the computed key “must be known.” The recognized API enum omits when (libs/extractor/src/stylex.rs:15-41).
    • 수정 방향: Implement marker values plus computed-key evaluation for each contextual selector and preserve StyleX's specificity ordering.
  • SX-10 (P1, WRONG) marker APIs escape to runtime
    • 근거: Transformed code still contains stylex.defaultMarker() / stylex.defineMarker() and runtime .flat(...).join(...); no marker CSS/value is generated.
    • 수정 방향: Recognize both APIs, generate deterministic marker references, and consume them from props and when.* without runtime StyleX calls.
  • SX-12 (P1, ERR-gap) media-query constants cannot form contextual keys
    • 근거: [constants.query] where query is '@media (min-width: 600px)' errors that the key must be known, though direct constant values work.
    • 수정 방향: Resolve computed keys through the same local/imported constant evaluator already used for declaration values.
  • VE-02 (P1, ERR-gap) globalKeyframes is declared but not callable
    • 근거: globalKeyframes('fade-global', {...}) → JS execution error: TypeError: not a callable function. register_vanilla_extract_apis registers no such function (libs/extractor/src/vanilla_extract.rs:604-665), while packages/react/src/compat/vanilla-extract.d.ts:25-38 declares it.
    • 수정 방향: Register and serialize globalKeyframes(name, frames) in the Boa API; align the ambient declaration and add a stylesheet probe test.
  • VE-05 (P1, ERR-gap) css-utils cannot be evaluated in stylesheet mode
    • 근거: Importing calc from @vanilla-extract/css-utils gives Cannot load '@vanilla-extract/css-utils' without a module resolver; the default alias table contains only @vanilla-extract/css.
    • 수정 방향: Statically evaluate this pure utility surface, or resolve the package through the stylesheet module resolver and guarantee deterministic output.

선택 (3)

  • EMO-07 (P2, WRONG) Emotion label is discarded in objects and emitted as an invalid CSS declaration in templates
    • 근거: react-label-object.tsx yields .a{color:red} with no readable suffix; react-label-template.tsx yields .a{label:template-name}
    • 수정 방향: parse and remove label from rule generation; append a sanitized label only in a compatibility/debug naming mode, or document deterministic minified names and consistently discard it without invalid CSS
  • SX-11 (P2, ERR-gap) stylex.env configuration substitution is absent
    • 근거: stylex.env.tokens.colors.primary in create errors that it is not a literal, theme token, or constant; env is not a recognized API.
    • 수정 방향: Add an explicit Devup StyleX environment option and static member substitution, or document this experimental API as unsupported with a targeted diagnostic.
  • VE-03 (P3, MISMATCH) style debugId is accepted but ignored
    • 근거: style({color:'red'}, 'root debug') under --debug yields class color-0-red--255; sibling APIs produce --token_debug-0-0, area_debug-0-1, and utilities_debug-0-2.
    • 수정 방향: Carry style debug IDs into Devup debug class naming, or document that style debug IDs are intentionally not preserved.

제외 (3)

  • EMO-17 (P2, ERR-gap) Computed styled tag access remains a runtime read of an erased binding (KNOWN-13)
    • 근거: styled-bracket.tsx errors that styled is read at runtime
    • 수정 방향: accept static computed string members in styled-factory recognition; retain the explicit error for dynamic computed keys
  • SX-13 (P2, MISMATCH) alternate StyleX resolution policy is unavailable
    • 근거: Shorthand/longhand output gives the longhand fixed later stylesheet order in both application orders; no Devup plugin option maps StyleX styleResolution.
    • 수정 방향: Either expose and implement the option or document that Devup targets only the default policy and reject incompatible configuration expectations.
  • SX-14 (P3, MISMATCH) Devup exposes a non-StyleX include() extension
    • 근거: ...stylex.include(base.root) compiles successfully and is exported in Devup's compatibility surface, but the official API index has no JavaScript include; official include is a PostCSS path/glob option.
    • 수정 방향: Document and namespace the extension, or remove it from claims of StyleX API parity.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions