Skip to content

[Feature]: SSR interactive-directive parity (bq-model, bq-on) or a documented boundary #128

Description

@JosunLP

Pre-flight checklist

  • I searched existing issues and did not find a duplicate request.
  • I explained the problem or use case, not just the desired API.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ssrChanges to the ssr module

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions