re-frame.ssr¶
Server-side rendering and hydration. re-frame.ssr runs the same framework as the client: the same registrations, cascade, app-db, and subs. Four things differ on the server:
- each request creates a per-request frame;
- the cascade runs to completion before the response is built;
- the resulting hiccup is emitted as an HTML string;
- a hydration payload ships alongside, so the client resumes without re-rendering.
Ships in a separate artefact (day8/re-frame2-ssr); add it to your deps and require the namespace. The Ring host-adapter lives in re-frame.ssr.ring.
The re-frame.core facade re-exports a curated set of render and head primitives as late-bound wrappers: rf/render-to-string, rf/render-tree-hash, rf/project-error, the registration macros rf/reg-head / rf/reg-error-projector, and the head accessors rf/render-head / rf/active-head / rf/head-model->html / rf/head-snapshot (accessors documented in re-frame.core). When the artefact is on the classpath, these wrappers resolve to this namespace at call time. When it is not, they throw a clear "SSR not loaded" error. Examples below use rf/ at idiomatic call sites and ssr/ for the host-adapter surface.
Rendering primitives¶
render-to-string¶
- Kind: function
- Signature:
- Description: The canonical server-side render. Walks the hiccup tree once and emits a string. Pure and JVM-runnable.
- It resolves registered views,
:tag#id.clsshorthand, and HTML5 void elements. It escapes text and attribute values. optskeys (all optional)::doctype?— prefixes<!DOCTYPE html>.:emit-hash?— injectsdata-rf-render-hashon the tree's first DOM-tag element, for client-side mismatch detection.:render-hash— supplies a precomputed hash to stamp instead, avoiding a second canonical-EDN walk.
- Raises:
:rf.error/invalid-tag-name— malformed tag name.:rf.error/ssr-invalid-attribute-name— malformed attribute key.:rf.error/ssr-raw-text-in-body— a raw string child of a body-position<script>/<style>.:rf.error/ssr-reagent-native-head— a:>interop head.:rf.error/ssr-suspense-boundary-outside-stream— a:rf/suspense-boundarymarker reached this non-streaming emitter.
- Example:
render-tree-hash¶
- Kind: function
- Signature:
- Description: A deterministic structural fingerprint of a render tree. The same canonical-EDN representation produces the same hash on JVM and CLJS. This hash drives the hydration compatibility check: a server/client hash mismatch means hydration is unsafe.
- Example:
install-render-to-string!¶
- Kind: function
- Signature:
- Description: Install this namespace's
render-to-stringinto a substrate adapter's:render-to-stringslot. Use it when wiring a custom (non-bundled) adapter directly. The bundled Reagent adapter wires itself via the:reagent/set-hiccup-emitter!late-bind hook, so app code rarely calls this.
adapter¶
- Kind: var
- Signature:
- Description: The SSR substrate adapter map: the server-side / headless (JVM) substrate. Pass it to
rf/init!to install it. - It carries this namespace's
render-to-stringdirectly in its:render-to-stringslot, so no late-bind wiring is needed at the call site. - Its
:renderslot throws:rf.error/render-on-headless-adapter. SSR renders exclusively viarender-to-string. - Example:
Streaming render¶
Streaming emits the shell HTML first, then continues rendering boundary subtrees as their data settles. The render tree marks boundaries with :rf/suspense-boundary. Each boundary becomes a continuation.
streaming-render-shell¶
- Kind: function
- Signature:
- Description: Walk the tree once. At each
:rf/suspense-boundary, it emits a<template …suspense-fallback>placeholder and records a continuation. Returns the shell HTML (ready to flush) and the continuations to drain. - Example:
streaming-render-continuation¶
- Kind: function
- Signature:
- Description: Drain one continuation against
frame-id's app-db. - It snapshots before-db / after-db and computes the per-subtree delta.
- A nested
:rf/suspense-boundaryinside the subtree registers a new continuation. New continuations come back under:continuations, for the host to append at the tail of its FIFO drain queue ([]when the subtree carries none). - On a throw, it emits
:rf.ssr/suspense-boundary-failed, surfaces the original fallback HTML inline with:failed? true, omits:delta, and returns no nested continuations. - Example:
;; Drain the FIFO queue against fid's app-db, emitting each chunk; ;; nested boundaries discovered mid-drain append at the tail. (loop [queue continuations] (when-let [entry (first queue)] (let [{:keys [id html delta failed? continuations]} (rf/with-frame fid (ssr/streaming-render-continuation fid entry))] ;; flush this subtree's resolved HTML + hydrate-delta as the next chunk (recur (into (vec (rest queue)) continuations)))))
streaming-build-final-payload¶
- Kind: function
- Signature:
- Description: Build the
__rf_payloadfinal chunk. Call it after all continuations drain. optsMUST carry the fail-closed:payloadpolicy: a vector allowlist of top-level app-db keys, or:rf.ssr.payload/whole-app-dbto ship the whole app-db. Omitting it throws:rf.error/ssr-missing-payload-policy.- Optional
:versionoverrides the:rf2/runtime-versionlate-bind hook as the payload's:rf/versionsource. - Example:
The next four functions are the lower-level chunk-template builders the streaming host emits per boundary. They are host-adapter territory; app code rarely calls them.
streaming-fallback-template¶
- Kind: function
- Signature:
- Description: The fallback chunk shape: the boundary's fallback markup, wrapped in an inline
<template data-rf2-suspense-fallback>placeholder in the shell HTML. A<template>'s content is inert (never painted), which makes it the wire-carrier for the fallback markup. The client-side streaming runtime materialises each inert fallback into a live, visible mount.
streaming-resolved-template¶
- Kind: function
- Signature:
- Description: The resolved-subtree chunk shape, flushed when a continuation drains successfully. The client-side streaming runtime swaps the matching fallback placeholder for this resolved content in the DOM.
streaming-failed-template¶
- Kind: function
- Signature:
- Description: The failed-continuation chunk shape: the same wire shape as
streaming-resolved-template, plus adata-rf2-suspense-failedmarker. The failure semantics are inline-fallback: the client-side runtime surfaces the failure observably, without surfacing a 500.
streaming-hydrate-delta-script¶
- Kind: function
- Signature:
- Description: The per-subtree hydration delta chunk (
application/edn). The client reads the EDN and merges the delta intoapp-dbas the subtree streams in.
The streaming surface is host-adapter territory. The SSR-aware host (re-frame.ssr.ring or equivalent) wires it, so most app code never touches streaming-render-* directly. The one app-facing piece is the client-side runtime, below.
streaming-install!¶
- Kind: function (ClojureScript only)
- Signature:
- Description: Install the client-side streaming runtime. Returns a 0-arity
stop!fn that disconnects the observer early. Idempotent per chunk. - It observes the document for arriving chunks. As they land, it materialises each inert fallback
<template>into a visible mount, swaps in resolved subtrees, and merges each per-subtree hydration delta into the:frame's app-db. - It disconnects itself once the final
__rf_payloadnode lands. From there, the bootstrap's:rf/hydrateis the canonical reconciliation. opts::frame— REQUIRED. An absent frame emits + throws:rf.error/no-frame-context.:root— the DOM root to observe; defaultjs/document.:payload-id— the final-payload<script>id; default"__rf_payload".
- Example:
The head model¶
The <head> is modelled separately from the body as a head-model: a data structure carrying :title, :meta, :link, :json-ld, :html-attrs, and :body-attrs. Head-models are registered per-route with reg-head. A registered head-fn is evaluated and rendered through the re-frame.core facade accessors render-head / active-head / head-model->html / head-snapshot (documented in re-frame.core). The :rf/head subscription returns the active route's head-model.
reg-head¶
- Kind: macro
- Signature:
- Description: Register a head-fn keyed by id. The head-fn signature is
(fn [db route] head-model). Routes opt in via:headroute metadata. - Example:
Exposed on the re-frame.core facade as rf/reg-head; there is no re-frame.ssr/reg-head alias. The brief facade entry in re-frame.core points here for the full contract.
Hydration¶
The server-rendered HTML carries a __rf_payload chunk that the client deserialises into app-db on bootstrap. The render-tree-hash structural hash is captured at render time and re-checked at hydration.
Three checks guard hydration, each with its own trace:
:rf.ssr/hydration-mismatch— the server-render hash disagrees with the client-render hash. In:hard-errormode it also throws; otherwise it warns and re-renders client-side, rather than mounting a broken DOM.:rf.ssr/version-mismatch— the payload was produced by a different framework version.:rf.ssr/schema-digest-mismatch— the app's schema set drifted since the payload was built.
The latter two are payload-provenance checks; the reference :rf/hydrate handler runs them. hydration-mismatch guards the render-tree structural hash. See the SSR tutorial §The client side.
hydrate!¶
- Kind: function
- Signature:
- Description: The client-side boot helper, and the symmetric counterpart of the server's
re-frame.ssr.ring/ssr-handler. Returns the payload that was applied, ornilon a client-only first load. It fuses the three mandated client-flow steps: - read the payload — supplied via
:payload, or on CLJS read from the DOM's__rf_payload<script>viaread-server-payload. - hydrate via
dispatch-sync [:rf/hydrate payload]against the target:framebefore the first render (locked:replace-frame-statesemantics). - verify by calling the supplied
:render-tree-fnand comparing its hash against the server hash (omit:render-tree-fnto skip). :frameis REQUIRED — an absent frame emits + throws:rf.error/no-frame-context.- A payload whose
:rf/frame-idnames a different frame than:frameemits + throws:rf.error/hydration-frame-id-mismatch. :payloadis required on the JVM and optional on CLJS (read from the DOM when omitted).:element-idoverrides the payload<script>id.- Example:
read-server-payload¶
- Kind: function (ClojureScript only)
- Signature:
- Description: Read the EDN hydration payload from the DOM's
__rf_payload<script>. That id is the pinned default; passelement-idto read a host-overridden slot.hydrate!calls this when:payloadis omitted. - Returns the parsed payload map, or
nilwhen the page was not server-rendered (no payload script present). - Fails closed: a malformed payload script surfaces
:rf.error/malformed-hydration-payloadand returnsnil, so the host falls back to a client-only first render. - Example:
verify-hydration!¶
- Kind: function
- Signature:
- Description: Called by client code after the first render. It compares the post-render hash to the server hash stashed during
:rf/hydrate, and emits:rf.ssr/hydration-mismatchon disagreement.hydrate!calls this for you when given a:render-tree-fn. Call it directly when the host must verify the actually-mounted tree. - The second argument may be a render tree (it is hashed) or a pre-computed hash string.
optsmay carry:first-diff-path,:failing-id, and:server-hash(the last overrides the stashed slot).- Two per-frame
:ssrknobs govern behaviour.{:detect-mismatch? false}skips the comparison.{:on-mismatch :hard-error}escalates a detected mismatch to a thrown structured exception; the default:warnresolves to:warned-and-replaced. - Example:
Error projection¶
A frame opts into SSR error projection via the :ssr {:public-error-id ... :dev-error-detail? ...} map on its make-frame / frame-root config. This is per-frame metadata, not a configure key: different frames in the same process can carry different projector / dev-detail settings.
reg-error-projector¶
- Kind: function
- Signature:
- Description: Register a projector keyed by id. The projector signature is
(fn [trace-event] :rf/public-error). Named per-frame via the frame's:ssr {:public-error-id ...}metadata. Returnsid. - Example:
Exposed both as the re-frame.core facade macro rf/reg-error-projector and as the re-frame.ssr/reg-error-projector function; the brief facade entry in re-frame.core points here for the full contract.
project-error¶
- Kind: function
- Signature:
- Description: Apply the named frame's active error-projector to a trace event. The projector is selected by the frame's
:ssr {:public-error-id ...}metadata. This is the seam between an internal error trace event (full diagnostic detail) and a client-safe public-error projection. - When the frame's
:ssr {:dev-error-detail? true}metadata is set, the projection carries an extra:detailskey with the raw trace event (absent by default). - If the projector throws or returns a non-conforming shape, this emits
:rf.error/sanitised-on-projectionand returns the locked generic-500fallback-public-error. A bug in the projector cannot bypass the boundary. reg-error-projector(above) registers the projector this applies.- Example:
default-error-projector-fn¶
- Kind: function
- Signature:
- Description: The runtime's built-in default projector, registered under
:rf.ssr/default-error-projector. Maps trace events to public errors: :rf.error/no-such-handler,:rf.error/no-such-route→404 :not-found.:rf.error/cofx-value-invalid(a client-supplied coeffect rejected at the dispatch boundary) →400 :bad-request.:rf.error/schema-validation-failure→400 :bad-request, but only when the failure's:wheretag is:event(a client-supplied event payload). Server-side surfaces such as:where :fx-argsfall through.- Everything else → the locked generic
500 :internal-error(fallback-public-error).
apply-error-projection!¶
- Kind: function
- Signature:
- Description: Project an error trace event via
frame-id's active projector, and stamp the resulting public-error's:statusonto the response accumulator. Returns the public-error map. Returnsnilon a no-op: the frame is missing, is not a server frame, or has no pending trace. - 1-arity: drains the frame's error-trace buffer and projects the LAST trace (last-write-wins).
- 2-arity: projects the supplied trace directly (for hosts that catch errors outside the trace stream).
- When the response already carries a
:redirect, its status is locked through. The projection still returns the public-error map, but does not overwrite:status.
project-render-exception!¶
- Kind: function
- Signature:
- Description: Route a render-time
Throwablethroughframe-id's SSR error projector. Host adapters wrap theirrender-to-stringcall with this. Returns the public-error map (the host's contract for rendering the wire error body), ornilwhen projection is not applicable. - It synthesises a
:rf.error/ssr-render-failedtrace carrying the exception, then drives the projector viaapply-error-projection!. The projector's output stamps the response accumulator's:status. - It also emits the trace, so monitoring listeners see the rich internal detail.
- The per-frame dev escape-hatch
:ssr {:on-view-exception :throw}re-throws unchanged instead of projecting.
public-error-keys¶
- Kind: var
- Signature:
- Description: The four locked keys on the
:rf/public-errorshape. Conformant projector output carries exactly these, plus an optional:detailsin dev mode.
fallback-public-error¶
- Kind: var
- Signature:
- Description: The locked generic-500 public-error shape. The runtime falls back to this whenever the active projector throws or returns a non-conforming shape. A bug in the projector cannot bypass the boundary.
Full rationale: the SSR tutorial §When the server throws.
The response accumulator¶
Each per-request frame accumulates its HTTP response (status, headers, cookies, redirect) in a framework-private side-channel keyed by frame-id. The accumulator lives outside app-db, so it never rides the hydration payload to the client. The server-only :rf.server/* fx write into it, and the functions below read the resolved value. get-response is the canonical host-adapter alias. peek-response and flush-response! split the pure read from the side-effecting drain.
default-response¶
- Kind: function
- Signature:
- Description: The default response accumulator: status
200, a defaultcontent-type: text/html; charset=utf-8header, no cookies, no redirect. - Example:
get-response¶
- Kind: function
- Signature:
- Description: Read the resolved response accumulator for a frame. This is the canonical host-adapter alias for the drain-then-read sequence: it flushes any pending error projections before reading, so
:statusreflects the active projector's output, and then strips the internal bookkeeping keys. Usepeek-responsefor a pure read (no drain) andflush-response!for the explicit-side-effect spelling. - Example:
peek-response¶
- Kind: function
- Signature:
- Description: A pure read of the resolved response accumulator. It does NOT drain pending error projections. Use it from debug paths or midpoint inspections, where the drain baked into
get-responsewould consume a trace the host had not yet observed.
flush-response!¶
- Kind: function
- Signature:
- Description: Drain any pending error projection for
frame-id, then return the resolved response. This is side-effecting: every call clears the projector buffer, and the first call after an error trace wins (last-write-wins). This is the explicit-side-effect spelling.get-responseis the canonical host-adapter alias;peek-responseis the pure-read counterpart.
Request context¶
An SSR host adapter populates a per-frame request slot once per request, before the drain. The :rf.server/request cofx surfaces it to server-side handlers. The slot is cleared as part of per-request frame teardown.
set-request!¶
- Kind: function
- Signature:
- Description: Populate the per-frame request slot. An SSR host adapter calls this once per request, before kicking off the drain. The shape of
requestis host-defined: the Ring adapter passes the Ring request map, and other adapters pass their native shape. The runtime never inspects it. - Example:
get-request¶
- Kind: function
- Signature:
- Description: Read the active request for
frame-id. Returnsnilwhen no host adapter has populated the slot. This is a public read surface: host adapters and tools may inspect the active request via this fn.
clear-request!¶
- Kind: function
- Signature:
- Description: Clear the per-frame request slot. Host adapters call this after building the wire response (typically as part of per-request frame teardown). Safe to call when no slot is populated.
on-frame-destroyed!¶
- Kind: function
- Signature:
- Description: The per-request frame teardown hook. It drops the frame's entries in the pending-error-trace buffer, the request slot, and the response slot, and it invokes the head-snapshot cleanup. It runs during per-request frame teardown via the
:ssr/on-frame-destroyedlate-bind hook. Idempotent: a second call against the same frame-id is a no-op.
Blocking-resource drain¶
drain-blocking-resources!¶
- Kind: function
- Signature:
- Description: Drain the current nav-token's BLOCKING resources for SSR
frame-iduntil they settle or the render deadline fires. This way the render walk sees a settled resource state, never a hung:loading. The host render path calls this after frame setup and route resolution, before the render walk. Returns the drain result map{:settled? :timed-out :route-blocking-failure}. - When the resources artefact is absent, this is a no-op returning
{:settled? true}. An SSR app without resources never blocks on them. optskeys (all optional)::ssr-blocking-timeout-ms— wall-clock budget; default5000.:pump!— a 1-arity(fn [tick-ms] …)event-pump thunk. Defaults to a host-platform yield, so an in-flight async reply lands between re-checks.:tick-ms— poll-granularity hint; default5.
- Example:
Keyword surfaces¶
The SSR runtime owns a set of keyword-addressed surfaces: events, server-only and client-only fx, subscriptions, one coeffect, and the :platforms registration-metadata key. These are addressed by keyword, not imported as vars.
Events¶
| Event | What it does |
|---|---|
:rf/server-init |
Per-request server-side initialisation. Reads request cofx; dispatches setup events. :platforms #{:server}. |
:rf/hydrate |
Seed the client-side app-db from the server-supplied payload (locked :replace-frame-state semantics). Runs once on client bootstrap. Fails closed. A non-map payload, or a present-but-non-map :rf/app-db / :rf/runtime-db slice, is rejected with :rf.error/malformed-hydration-payload. A payload :rf/frame-id naming a different frame than the dispatch target is rejected with :rf.error/hydration-frame-id-mismatch. In both cases the frame-state is left unchanged. |
- Example:
;; :rf/server-init — registered by the app; fired from the per-request frame's ;; :initial-events as it boots, dispatching the setup work the page needs. (rf/reg-event :rf/server-init {:platforms #{:server}} (fn [{:keys [db]} _] {:db db :fx [[:rf.http/managed {:request {:method :get :url "/api/articles"} :decode :json :on-success [:articles/loaded]}]]})) ;; :rf/hydrate — framework-owned; dispatched on the client (usually via ;; ssr/hydrate!) to seed app-db from the payload before the first render. (rf/dispatch-sync [:rf/hydrate payload] {:frame client-frame})
Server-only fx¶
All seven fx are server-only (:platforms #{:server}). They build the response accumulator that the host adapter turns into the HTTP response.
| Fx | Args |
|---|---|
[:rf.server/set-status int] |
per :rf.fx.server/set-status-args |
[:rf.server/set-header {:name :value}] |
per :rf.fx.server/set-header-args |
[:rf.server/append-header {:name :value}] |
per :rf.fx.server/append-header-args |
[:rf.server/set-cookie :rf.server/cookie] |
structured cookie map |
[:rf.server/delete-cookie {:name ?:path ?:domain}] |
— |
[:rf.server/redirect {:location ?:status}] |
default :status 302; truncates HTML. Caller-trusted :location. |
[:rf.server/safe-redirect {:location ?:relative-only? ?:allow ?:status}] |
The caller-untrusted variant: open-redirect mitigation for attacker-controlled ?next= strings. Before setting :redirect, it parses :location (:rf.error/safe-redirect-invalid-url), rejects javascript: / data: / vbscript: schemes (:rf.error/safe-redirect-scheme-rejected), and enforces the :relative-only? / :allow allowlist (:rf.error/safe-redirect-host-disallowed). |
Boundary validation (all seven):
- A header name violating the RFC 7230 token grammar throws
:rf.error/header-invalid-name. A header value carrying CR/LF/NUL throws:rf.error/header-invalid-value. - A cookie
:nameviolating the RFC 6265 token grammar, or of an unsupported type, throws:rf.error/cookie-invalid-name. Any other cookie attribute (:value/:path/:domain/:max-age/:same-site/:expires) carrying CR/LF/NUL throws the single:rf.error/cookie-invalid-attribute, which names the offending attribute in its:attributepayload slot. - A redirect
:locationcarrying CR/LF/NUL throws:rf.error/redirect-invalid-location. The retired:url/:totarget keys throw:rf.error/redirect-retired-target-key. -
:statusand:redirectare last-write-wins. A second write in the same drain emits:rf.warning/multiple-status-set/:rf.warning/multiple-redirects. -
Example:
;; Shape the HTTP response from a server-side handler. Every :rf.server/* fx ;; is :platforms #{:server}, so the client render skips them. (rf/reg-event :app/respond {:platforms #{:server}} (fn [{:keys [db]} _] {:db db :fx [[:rf.server/set-status 200] [:rf.server/set-header {:name "X-Foo" :value "first"}] [:rf.server/append-header {:name "Set-Cookie" :value "a=1"}] [:rf.server/set-cookie {:name "session" :value "abc123" :max-age 3600 :http-only true :same-site :lax :path "/"}] [:rf.server/delete-cookie {:name "stale-session" :path "/"}]]})) ;; Redirects — caller-trusted vs caller-untrusted (e.g. an attacker-supplied ;; ?next= param). safe-redirect parses + allowlists before setting :redirect. (rf/reg-event :auth/bounce {:platforms #{:server}} (fn [{:keys [db]} _] {:db db :fx [[:rf.server/redirect {:status 302 :location "/login"}] [:rf.server/safe-redirect {:location "/dashboard" :relative-only? true}]]}))
Client-only fx¶
Both fx are client-only (:platforms #{:client}). They are the payload-provenance compatibility checks that the reference :rf/hydrate handler dispatches after installing the server slice. They are best-effort: a mismatch emits a structured warning trace, and hydration proceeds.
| Fx | Args |
|---|---|
[:rf.ssr/check-version server-value] |
A scalar (the payload's :rf/version) or {:expected ?:actual}. When :actual is absent, the client value resolves via the :rf2/runtime-version late-bind hook. A mismatch emits :rf.ssr/version-mismatch. An unresolvable client value emits :rf.ssr/compatibility-check-skipped. |
[:rf.ssr/check-schema-digest server-value] |
A scalar (the payload's :rf/schema-digest) or {:expected ?:actual}. When :actual is absent, the client value resolves via the :schemas/app-schemas-digest late-bind hook (schemas artefact). A mismatch emits :rf.ssr/schema-digest-mismatch. An absent hook emits :rf.ssr/compatibility-check-skipped. |
Subscriptions¶
| Sub | Returns |
|---|---|
:rf/head |
The head model for the active route (resolved via active-head against the subscribed frame) |
:rf/public-error |
The sanitised public-error projection when an error page is being rendered; nil otherwise |
NOT USED —
:rf/headis never subscribed (no[:rf/head]call sites, and noreg-sub :rf/head) inimplementation/,examples/, ortools/.NOT USED —
:rf/public-erroris never subscribed (no[:rf/public-error]call sites, and noreg-sub :rf/public-error) inimplementation/,examples/, ortools/. The:rf/public-errormap shape is produced byproject-error; only the sub is unused.
The current request's response accumulator (status / headers / cookies / redirect) is not a registered subscription. It lives in a framework-private side-channel atom keyed by frame-id, and the runtime reads it exclusively via re-frame.ssr/get-response. The host adapter consumes the resolved value to build the wire response.
Coeffects¶
| Cofx | Returns |
|---|---|
:rf.server/request |
The active HTTP request map. |
- Example:
;; A server handler declares the requirement, then reads the request FLAT ;; under :rf.server/request (Ring-shaped under the bundled adapter). (rf/reg-event :app/server-init {:platforms #{:server} :rf.cofx/requires [:rf.server/request]} (fn [{:rf.server/keys [request] :keys [db]} _] {:db (assoc db :method (:request-method request))}))
:platforms fx-gating metadata¶
reg-fx accepts a :platforms metadata key: a set containing :server and / or :client. It gates fx execution by active platform. When the key is absent, the default is #{:server :client} (universal).
Skipped fx emit a :rf.fx/skipped-on-platform trace event so debug tools see the gate firing. The cofx side has a mirror trace event, :rf.cofx/skipped-on-platform.
Detail in the SSR tutorial §:platforms.
See also¶
re-frame.core— thereg-head/reg-error-projectorfacade entries and the head accessors (render-head/active-head/head-model->html/head-snapshot), plus the instrumentation / error-catalogue surface where the SSR trace events are defined.re-frame.ssr.ring— the Ring host adapter that drives the render pipeline and materialises the response accumulator onto the wire.re-frame.routing— routes opt into head models via:headmetadata.- Server-side rendering — the tutorial — the conceptual walkthrough.