Static-tag intrinsic: `<element tag={tag}>` for elements whose tag is fixed at definition time
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 45/100
- Tipo di issue
- Funzionalità
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- babel, typescript
- Ambito
- compilers, frontend, testing-qa
Direzione di ricerca
Inizia dagli entry point dei compilatori Babel e Oxc e dal lowering esistente di DOM, SSR e universal per i tag letterali e le radici spread. Segui i relativi test di parità dell’hydration e i typings di IntrinsicElements; il lavoro è completo quando la forma del tag viene validata e sottoposta a lowering in modo coerente, i tag mancanti generano un errore, il typing è strict e lo scenario di hydration passa su tutti i renderer.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Problem
Libraries that build components around a native element whose tag is fixed at definition time — styled.li, styled("button"), any design-system primitive factory — have no good way to render that element:
dynamic(() => tag)is the only isomorphic path from a tag string to an element. It pays a factory memo plus a per-instance memo (and a hydration id) for a value that never changes. In yak-bench's browser hydrate matrix, the lane that renders the styled element throughdynamic()is 1.47× slower (geomean) than the same code with the element compiled from a literal tag; everything else in the two lanes is identical. One memo per element is the entire gap.- A runtime factory (
element(tag)returning a component) removes the memos but can't take spreads natively: a use-site{...rest}has to be merged into a props object and crossed through a component boundary beforespread()sees it, and static attributes are walked instead of compiled. - Hand-rolling it means an
isServerfork over internals (getNextElement,runHydrationEvents,sharedConfig.hydratingvsssrElement), which is what next-yak/next-yak#644 did.
Profiling the composition-heavy SSR cases (tabs) shows Solid's own rendering at ~7% of time and props plumbing (merge, omit, proxies, and the GC they generate) at ~55%; the styled-element seam is where most of that plumbing is introduced.
Proposal
A reserved intrinsic whose tag comes from an in-scope identifier:
function styled(tag) {
return props => (
<element tag={tag} {...filtered(props)} class={cls(props)}>
{props.children}
</element>
);
}
The compiler lowers it exactly as it would a literal tag, with createElement(tag) in place of the template clone:
- DOM:
hydrating ? getNextElement() : createElement(tag);spread(el, [filtered, { get class() {…} }])(the sources array from #3419/#3423);insert(el, () => props.children);runHydrationEvents()when hydrating. Two reactive nodes with children, one without, zero memos. Static child subtrees compile to their own templates and are appended; dynamic children go throughinsert. - SSR:
ssrElement(tag, [filtered, { class }], () => props.children, true)— one walk (#3418),_hkon the element. Hydration ids stay aligned because both sides do exactly what a compiled spread root does today. - Universal: renderer
createElement(tag)+spread.
The string element never reaches the DOM or the SSR output; the compiler consumes it. <element> without tag is a compile error, not a fall-through to a real tag.
Static rule
tag is an expression evaluated once, untracked, when the element is created — the same contract as <Provider value>. It is never reactive, and the compiler does not try to prove it constant (a binding in an enclosing scope can be reassigned; constancy isn't globally provable, so a scope rule would restrict real code while guaranteeing nothing). The lowering reads it exactly once (createElement(tag) / ssrElement(tag, …)); later changes to whatever it was read from are ignored, as with value.
<element>withouttagis a compile error, not a fall-through to a real tag.dynamic()/<Dynamic component>remain the answer for a tag that can change; the per-instance memo is the price of being dynamic. The two features stay vocabulary-distinct (as→Dynamic,tag→element), and theIntrinsicElements.elementdoc comment states the read-once rule so it shows on hover.
Why not <element:tag>
The namespaced form was considered first — it has the nice property that JSXNamespacedName can only hold a bare identifier, so props.as is syntactically impossible. Both parsers accept it and TS 6.0.3 types it through a template-literal index signature. But TS treats element:tag as the string "element:tag": the variable is never bound, so noUnusedLocals/noUnusedParameters flag tag (TS6133, verified), unbound identifiers aren't errors, and rename/go-to-definition are blind. That is exactly the use: directive experience. Putting the tag in an expression position (tag={tag}) gives TS the binding; the read-once rule is a documented contract, as it is for <Provider value>.
Naming
element: not in HTML, SVG, or MathML, nor in Solid'sIntrinsicElementsor either compiler's tag tables. The only history is the Web Components v0 declarative<element name="x-foo">, removed from the spec in August 2013 and never shipped unflagged. Custom elements can't claim it (hyphen required).tag, notname:nameis a real attribute on the elements most likely to be wrapped (input,button,select,textarea,form,iframe, …) and is routinely forwarded through the spread; there is no HTML/SVG/MathML attribute calledtag.isis out for the same reason (customized built-ins; forwarded).
Typing
IntrinsicElements.element: HTMLAttributes<HTMLElement> & { tag: string }. Necessarily generic (no per-tag narrowing — the tag is a variable), ref is HTMLElement. Attribute checking, children, and ref all work under --strict; the doc comment carries the static rule so it shows on hover.
Non-goals
- Compile-time folding of fully static styled elements into strings (what yak does for its React build). Separate question.
- A reactive or async
tag. That isDynamic. - A runtime
element(tag)factory. Not needed once the syntax exists;h/htmlalready take string tags.
Plan
Babel + Oxc: DOM, SSR, universal lowering (missing tag is an error), shared test expectations (parity). IntrinsicElements.element typing. Parity-harness hydration scenario (server ssrElement ↔ client getNextElement + spread sources). yak-bench prim-element overlay switched to it for the before/after against the dynamic() lane.
— Claude via Cursor
- Lingua principale
- TypeScript
- Stelle
- 36.2k
- Fork
- 1.1k
- Merge medio
- 10h 10m
- PR unite (30g)
- 505
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di solidjs/solid
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 22/100
I maintainer di solito rispondono entro 1 giorno
-
What gets passed to the `when` prop of a `Show` still gets executed twice on SSRForse già presa @brenelz l’ha presa 3 giorni fa. Aperta1.x
Difficoltà 3/5 1-2 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
solidjs/solid#4447 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di solidjs/solid
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
riverqueue/river#1576 ·
I maintainer di solito rispondono entro 1 giorno
-
[bug] A prompt queued during a run is assessed without its textForse già presa @jwiegley l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
DevMortimer/pi-warden#211 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 84/100
mattermost/compass-design#191 ·
I maintainer di solito rispondono entro 1 giorno
-
Add unit tests for the organization admin role checkForse già presa @SaffuSafwan l’ha presa oggi. Apertaarea/core good first issue help wanted
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
elmohq/elmo#1095 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
HorusGoul/trizum#559 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno