Summary
packages/stx-native compiles .stx to a native view IR with its own lexer and parser (src/compiler/parser.ts, 742 lines). That parser is not stx's parser, and it cannot read real stx templates — so none of @stacksjs/components compiles. Going native today would mean rewriting all 102 components against <View>/<Text> primitives.
It does not need to. stx's own pipeline already produces exactly the right input.
Evidence
Feeding real library components to compileSTX:
| Component | Result |
|---|---|
packages/components/src/ui/button/Button.stx | throws Expected > or /> at line 54, got TEXT |
packages/components/src/ui/card/Card.stx | throws No root element found in template |
packages/components/src/ui/mobile/TabBar.stx | compiles to a single Text node, with a still in the IR |
The third is the dangerous one: it does not fail, it silently produces a wrong tree.
What the parser does not handle: <script server>, @if / @foreach, inside attributes, component composition, slots — i.e. most of what an stx component is.
The parser is not useless. Given a hand-written template of native primitives it is correct, and the headwind compiler behind it is genuinely good:
<View class="flex-1 flex-col justify-center items-center p-4 bg-blue-500">
<Text class="text-white text-lg font-bold">Wildloop</Text>
</View>{ "type": "View", "style": { "flex": 1, "flexDirection": "column", "justifyContent": "center",
"alignItems": "center", "padding": 16, "backgroundColor": "#3b82f6" },
"children": [ { "type": "Text", "style": { "color": "#ffffff", "fontSize": 18, "fontWeight": "bold" } } ] }The change
stx's renderer already emits output with client bindings intact — :show, x-text, @click survive into the HTML precisely so the signals runtime can bind them. That output is the right input for the native compiler:
mapToNativeComponent(src/compiler/parser.ts:672) already mapsdiv→View,span/p/h1→Text,button→Button,img→Image,input→TextInputcompileHeadwindToStylealready turns the class strings those components carry into native style- server scripts, directives, component expansion and slots are then handled by the pipeline that has 13,697 tests behind it, instead of by a second parser with none
Ask
- Replace the bespoke lexer/parser with a translator whose input is stx's rendered output (bindings preserved), not raw
.stx. - Keep
ir.ts,headwind-to-style.tsand the component mapping — they are the parts worth keeping. - Delete
Lexer/Parser/parseSTXonce the translator covers them, so there is one parser in the project rather than two that disagree.