← All posts
Fix

spark-html 1.8.2 + spark-ssr 1.3.4 — the known-issues sweep

We keep an honest known-issues table in the docs. This release sweeps it: three core bugs fixed, two spark-ssr fixes (one found while verifying the sweep), and two reports we could not reproduce — now marked that way in the table, with the correct behavior pinned by permanent tests.

spark-html 1.8.2 — three fixes

1. A boolean attribute bound to a falsy non-boolean stayed on. :disabled="col" with a SQLite 0 rendered disabled="0" — which is still disabled; presence is what counts for boolean attributes. The :attr patcher now knows the genuine HTML boolean attributes (disabled checked selected readonly required multiple hidden open): a falsy non-boolean removes them. Truthy strings keep their value (hidden="until-found" still works), and non-boolean attributes are untouched — :value="0" still renders value="0". No more :disabled="!!col" coercion.

2. An interpolated src/poster fetched the literal . On an imported component, the raw markup briefly held <img src="{url}"> before the first patch — and the browser fired a real request for /%7Burl%7D (a cosmetic but noisy 404 on any component whose data arrives async). The import path now parks those templates in the element's patch plan and blanks the attribute until the first patch writes the real value. Verified in a real browser: zero literal-brace requests, image loads once, with the final URL.

3. A loop variable passed as a prop to an imported component crashed hydration. An each nested inside a <template if> resolved its rows' import placeholders twice — once with the loop scope (correct) and once more by the if-block's own import sweep, whose scope doesn't have the loop variable: "h is not defined", plus a wasted duplicate fetch and boot. Placeholders are now claimed by the first resolver; nested blocks keep their own scope. Inlining child markup as a workaround is no longer needed.

spark-ssr 1.3.4 — two fixes

1. Boolean attributes, mirrored server-side. The same falsy-non-boolean rule now applies in the server renderer, with the same attribute list — otherwise SSR and the hydrated client would disagree about the attribute.

2. An interactive page with zero data sources was served dead. A page with handlers and binds but no <spark-ssr> source didn't hydrate at all: handlers stripped server-side, no client component, no warning. It's a client page that happens to live in pages/ — it now hydrates like any other interactive page. (Found while verifying this sweep; it never bit real apps because real pages have sources.)

While in there, we re-reviewed 1.3.1's live-on-raw-writes feature end to end. The design held up — per-request coalescing, flush in finally, opt-in broadcast gating — but the SQL classifier had two gaps, now fixed: a CTE-led write (WITH … INSERT/UPDATE/DELETE) was classified as a read and silently skipped the live ping, cache invalidation, and job hooks; and a leading SQL comment made an insert fire hooks under the generic write event, so on="insert:table" jobs missed it.

Update — spark-ssr 1.3.5 (same day): porting the fixes back into the San-App example surfaced one more live gap: background jobs ran with the unwrapped db, so a job's writes (an hourly payout notifier, an on-insert hook) never pinged live tabs or invalidated caches. Jobs now get the same coalesced live automation as custom endpoints — hookless, so a job writing its own trigger table can never loop.

The two we could not reproduce

Two reports from the San-App port — bind:value losing its value inside a display:none-toggled container, and interpolated width/height on a raw <svg> coming back empty after hydration — did not reproduce on 1.7.0, 1.8.0, or 1.8.1, across client-only, prerender-style hydration, spark-ssr hydration, a hydrating layout, and template if-nested shapes, in a real Chromium. Rather than claim a fix we can't verify, the table now marks both (unconfirmed), the correct behavior is pinned by permanent suite tests, and we'd love a minimized repro if you can trigger either.

Verifying it

Every fix ships with a regression test (the import double-resolve and eager-src ones poll mid-mount, so a revert fails loudly), and the whole chain ran green: the 500-scenario fuzzer, scanner fuzzer, all package suites, the SSR security and bench suites (render floor intact), the relocation e2e (client / ssr / prerender converge), and the budget gate:

112 passed, 0 failed (spark-ssr)
500 passed, 0 failed (fuzz)
spark-html runtime: 18.00 KB gzip · budget 18 KB
✅ within budget

That last line is exact — the three fixes cost bytes, so two verbose dev warnings got shorter to pay for them. The 18 KB ceiling doesn't move.

Upgrading

Both are pure bug-fix releases, no breaking changes:

npm install spark-html@^1.8.2
bun add spark-ssr@^1.3.5

Details: spark-html on npm · spark-ssr on npm · v1.8.2 · ssr-v1.3.4.