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-escapedBrowser: 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 orJSON.stringifyresult 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.