Summary
{{ expr }} interpolation inside a <script client> block is HTML-escaped, so any interpolated value containing quotes (e.g. a string or JSON.stringify(...) output) is emitted as invalid JavaScript. " becomes ", which breaks the whole client bundle with Unexpected token '&' / missing ) after argument list.
This makes every @stacksjs/components component that injects a server prop into a client signal unusable — Notification, Dialog, Drawer, Tabs, Tooltip, Switch, Select, Pagination, Accordion, etc. all use this pattern (const x = state({{ initialX }}), const cls = {{ JSON.stringify(className) }}), and dropping any of them onto a page crashes that page's JS.
Versions: @stacksjs/stx 0.2.70, bun-plugin-stx 0.2.70, @stacksjs/components 0.2.70 (note: components@0.2.70 pins stx@0.2.70 — same monorepo — so the shipped components are broken against their own engine). Also reproduced on 0.2.72. Bun 1.3.13, macOS arm64.
Minimal reproduction
components/ReproWidget.stx:
<script server>
export const initialShow = $props.show !== false
export const className = $props.className || ''
</script>
<script client>
const isVisible = state({{ initialShow }})
const extraClassName = {{ JSON.stringify(className) }}
function toggle() { isVisible.set(!isVisible()) }
</script>
<div :if="isVisible()" role="alert">widget visible</div>
views/index.stx:
<!DOCTYPE html><html><head><title>repro</title></head>
<body>
<ReproWidget show className="foo" />
</body></html>
Serve with bun-plugin-stx/serve and open the page.
Actual compiled client JS
const isVisible = state(true); // OK — `true` has no special chars
const extraClassName = "foo"; // BROKEN — quotes HTML-escaped
Browser: Uncaught SyntaxError: Unexpected token '&'. The entire client bundle fails to execute, so the whole page is dead (no signals, no event handlers).
Expected
Interpolation inside a <script client> (and <script server>) block must not HTML-escape. The line should compile to:
const extraClassName = "foo";
i.e. {{ }} inside script context should behave like {!! !!} (raw), since script content is JavaScript, not HTML text.
Impact / why it matters
state({{ initialShow }}) happens to work only because booleans/numbers have no escapable characters; the moment a string or JSON.stringify result is injected, the bundle breaks.
- This blocks all of
@stacksjs/components' interactive components on a vanilla install.
Workaround
None from userland — the affected code is inside node_modules/@stacksjs/components. Consumers can only use purely server-rendered components (e.g. Spinner, Badge, Card).
Related
Same {{ }}-in-components family as #1748 ({{ }} inside x-for renders empty in components), but this one corrupts script output rather than rendering blank.
Summary
{{ expr }}interpolation inside a<script client>block is HTML-escaped, so any interpolated value containing quotes (e.g. a string orJSON.stringify(...)output) is emitted as invalid JavaScript."becomes", which breaks the whole client bundle withUnexpected token '&'/missing ) after argument list.This makes every
@stacksjs/componentscomponent that injects a server prop into a client signal unusable —Notification,Dialog,Drawer,Tabs,Tooltip,Switch,Select,Pagination,Accordion, etc. all use this pattern (const x = state({{ initialX }}),const cls = {{ JSON.stringify(className) }}), and dropping any of them onto a page crashes that page's JS.Versions:
@stacksjs/stx0.2.70,bun-plugin-stx0.2.70,@stacksjs/components0.2.70 (note: components@0.2.70 pins stx@0.2.70 — same monorepo — so the shipped components are broken against their own engine). Also reproduced on 0.2.72. Bun 1.3.13, macOS arm64.Minimal reproduction
components/ReproWidget.stx:views/index.stx:Serve with
bun-plugin-stx/serveand open the page.Actual compiled client JS
Browser:
Uncaught SyntaxError: Unexpected token '&'. The entire client bundle fails to execute, so the whole page is dead (no signals, no event handlers).Expected
Interpolation inside a
<script client>(and<script server>) block must not HTML-escape. The line should compile to:i.e.
{{ }}inside script context should behave like{!! !!}(raw), since script content is JavaScript, not HTML text.Impact / why it matters
state({{ initialShow }})happens to work only because booleans/numbers have no escapable characters; the moment a string orJSON.stringifyresult is injected, the bundle breaks.@stacksjs/components' interactive components on a vanilla install.Workaround
None from userland — the affected code is inside
node_modules/@stacksjs/components. Consumers can only use purely server-rendered components (e.g.Spinner,Badge,Card).Related
Same
{{ }}-in-components family as #1748 ({{ }}insidex-forrenders empty in components), but this one corrupts script output rather than rendering blank.