Pre-flight checklist
Problem or use case
renderToString() documents support for a subset of directives (bq-text, bq-html, bq-if, bq-show, bq-for, bq-class, bq-style, bq-bind:*) and notably omits the interactive directives bq-model and bq-on. A component authored with two-way binding or event handlers therefore renders differently on the server than it behaves on the client, which produces hydration divergence and forces authors to keep two mental models of what works where. This subset behavior is a concrete blocker to ssr reaching Stable (#127), because "renders a directive subset only" is not a contract teams can build on.
Proposed solution
Either (a) extend server rendering so the full view-directive set produces correct, hydration-ready markup — emitting initial values for bq-model and the appropriate hydration markers for bq-on so the client can attach listeners on hydrate — or (b) if some directives are intentionally client-only, formalize that as an explicit, enforced, documented boundary with a dev-time warning when an unsupported directive is encountered during SSR. Parity (a) is strongly preferred for the "one stack" promise; the explicit boundary (b) is the minimum acceptable outcome.
Possible API or UX shape
import { renderToString } from "@bquery/bquery/ssr";
// bq-model emits the current value into the server markup;
// bq-on emits a hydration marker, listeners attach on hydrate.
const html = renderToString(view, {
directives: "full", // "full" | "static" (current behavior)
onUnsupportedDirective: "warn" // "warn" | "throw" | "ignore"
});
Alternatives considered
Documenting the omission in prose only (status quo) — insufficient, because it is silent at runtime and surfaces as confusing hydration bugs. Asking users to avoid bq-model/bq-on in SSR components — defeats the purpose of a unified client/server view layer and has no parity in Svelte/Vue, both of which render their binding and event constructs server-side.
Relevant area
ssr
Additional context
Hydration correctness depends on this: today verifyHydration only warns in dev (see #130). Vue renders v-model/v-on constructs server-side and reconciles on hydration; Svelte does the same for bind:/on:. Closing this gap is what makes bQuery's SSR comparable rather than a static-render subset.
Pre-flight checklist
Problem or use case
renderToString()documents support for a subset of directives (bq-text, bq-html, bq-if, bq-show, bq-for, bq-class, bq-style, bq-bind:*) and notably omits the interactive directivesbq-modelandbq-on. A component authored with two-way binding or event handlers therefore renders differently on the server than it behaves on the client, which produces hydration divergence and forces authors to keep two mental models of what works where. This subset behavior is a concrete blocker tossrreaching Stable (#127), because "renders a directive subset only" is not a contract teams can build on.Proposed solution
Either (a) extend server rendering so the full view-directive set produces correct, hydration-ready markup — emitting initial values for
bq-modeland the appropriate hydration markers forbq-onso the client can attach listeners on hydrate — or (b) if some directives are intentionally client-only, formalize that as an explicit, enforced, documented boundary with a dev-time warning when an unsupported directive is encountered during SSR. Parity (a) is strongly preferred for the "one stack" promise; the explicit boundary (b) is the minimum acceptable outcome.Possible API or UX shape
Alternatives considered
Documenting the omission in prose only (status quo) — insufficient, because it is silent at runtime and surfaces as confusing hydration bugs. Asking users to avoid
bq-model/bq-onin SSR components — defeats the purpose of a unified client/server view layer and has no parity in Svelte/Vue, both of which render their binding and event constructs server-side.Relevant area
ssrAdditional context
Hydration correctness depends on this: today
verifyHydrationonly warns in dev (see #130). Vue rendersv-model/v-onconstructs server-side and reconciles on hydration; Svelte does the same forbind:/on:. Closing this gap is what makes bQuery's SSR comparable rather than a static-render subset.