sx-http: SX adapter for all SSR — islands render correctly
Switch SSR + shell from native Sx_render to SX adapter (render-to-html from adapter-html.sx) via CEK evaluator. Handles reactive primitives (signals, deref, computed) for island bodies. Native renderer as fallback. Header island SSRs correctly: (<sx>), tagline, copyright, path. Stepper renders body but ~cssx/tw shows as raw SX (client-affinity component not expanded server-side, client not expanding either). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1517,29 +1517,30 @@ let http_render_page env path =
|
|||||||
| String s | SxExpr s -> s
|
| String s | SxExpr s -> s
|
||||||
| _ -> serialize_value body_result
|
| _ -> serialize_value body_result
|
||||||
in
|
in
|
||||||
(* Debug: dump aser for homepage *)
|
|
||||||
if path = "/sx/" then begin
|
|
||||||
try
|
|
||||||
let oc = open_out "/tmp/sx-aser-home.txt" in
|
|
||||||
output_string oc body_str;
|
|
||||||
close_out oc;
|
|
||||||
Printf.eprintf "[debug] Wrote aser for %s: %d bytes\n%!" path (String.length body_str)
|
|
||||||
with _ -> ()
|
|
||||||
end;
|
|
||||||
let t2 = Unix.gettimeofday () in
|
let t2 = Unix.gettimeofday () in
|
||||||
(* Phase 2: SSR — render to HTML using streaming buffer renderer.
|
(* Phase 2: SSR — render to HTML using the SX adapter (render-to-html
|
||||||
Writes directly to buffer, no intermediate string allocations. *)
|
from adapter-html.sx) via the CEK evaluator. This handles reactive
|
||||||
|
primitives (signals, deref, computed) correctly for island SSR.
|
||||||
|
Falls back to native Sx_render if the SX adapter isn't available. *)
|
||||||
let body_html =
|
let body_html =
|
||||||
try
|
try
|
||||||
let body_exprs = Sx_parser.parse_all body_str in
|
let body_exprs = Sx_parser.parse_all body_str in
|
||||||
let body_expr = match body_exprs with
|
let body_expr = match body_exprs with
|
||||||
| [e] -> e | [] -> Nil | _ -> List (Symbol "<>" :: body_exprs) in
|
| [e] -> e | [] -> Nil | _ -> List (Symbol "<>" :: body_exprs) in
|
||||||
let buf = Buffer.create 65536 in
|
if env_has env "render-to-html" then begin
|
||||||
(try Sx_render.render_to_buffer buf body_expr env
|
(* SX adapter — handles signals, islands, CSSX *)
|
||||||
with e -> Printf.eprintf "[http-ssr] partial for %s: %s\n%!" path (Printexc.to_string e));
|
let render_call = List [Symbol "render-to-html";
|
||||||
Buffer.contents buf
|
List [Symbol "quote"; body_expr];
|
||||||
|
Env env] in
|
||||||
|
let result = Sx_ref.eval_expr render_call (Env env) in
|
||||||
|
match result with
|
||||||
|
| String s | RawHTML s -> s
|
||||||
|
| _ -> Sx_runtime.value_to_str result
|
||||||
|
end else
|
||||||
|
(* Fallback: native renderer *)
|
||||||
|
Sx_render.render_to_html_streaming body_expr env
|
||||||
with e ->
|
with e ->
|
||||||
Printf.eprintf "[http-ssr] failed: %s\n%!" (Printexc.to_string e); ""
|
Printf.eprintf "[http-ssr] failed for %s: %s\n%!" path (Printexc.to_string e); ""
|
||||||
in
|
in
|
||||||
let t3 = Unix.gettimeofday () in
|
let t3 = Unix.gettimeofday () in
|
||||||
(* Phase 3: Shell — render directly to buffer for zero-copy output *)
|
(* Phase 3: Shell — render directly to buffer for zero-copy output *)
|
||||||
@@ -1567,7 +1568,19 @@ let http_render_page env path =
|
|||||||
Keyword "meta-html"; String "";
|
Keyword "meta-html"; String "";
|
||||||
] in
|
] in
|
||||||
let shell_call = List (Symbol "~shared:shell/sx-page-shell" :: shell_args) in
|
let shell_call = List (Symbol "~shared:shell/sx-page-shell" :: shell_args) in
|
||||||
let html = Sx_render.render_to_html_streaming shell_call env in
|
(* Use SX adapter for shell too — it's an SX component *)
|
||||||
|
let html =
|
||||||
|
if env_has env "render-to-html" then begin
|
||||||
|
let render_call = List [Symbol "render-to-html";
|
||||||
|
List [Symbol "quote"; shell_call];
|
||||||
|
Env env] in
|
||||||
|
let result = Sx_ref.eval_expr render_call (Env env) in
|
||||||
|
match result with
|
||||||
|
| String s | RawHTML s -> s
|
||||||
|
| _ -> Sx_runtime.value_to_str result
|
||||||
|
end else
|
||||||
|
Sx_render.render_to_html_streaming shell_call env
|
||||||
|
in
|
||||||
let t4 = Unix.gettimeofday () in
|
let t4 = Unix.gettimeofday () in
|
||||||
Printf.eprintf "[sx-http] %s route=%.3fs aser=%.3fs ssr=%.3fs shell=%.3fs total=%.3fs html=%d\n%!"
|
Printf.eprintf "[sx-http] %s route=%.3fs aser=%.3fs ssr=%.3fs shell=%.3fs total=%.3fs html=%d\n%!"
|
||||||
path (t1 -. t0) (t2 -. t1) (t3 -. t2) (t4 -. t3) (t4 -. t0) (String.length html);
|
path (t1 -. t0) (t2 -. t1) (t3 -. t2) (t4 -. t3) (t4 -. t0) (String.length html);
|
||||||
@@ -1733,9 +1746,7 @@ let http_inject_shell_statics env static_dir sx_sxc =
|
|||||||
(String.length pages_sx)
|
(String.length pages_sx)
|
||||||
(List.length (String.split_on_char '\n' pages_sx));
|
(List.length (String.split_on_char '\n' pages_sx));
|
||||||
ignore (env_bind env "__shell-pages-sx" (String pages_sx));
|
ignore (env_bind env "__shell-pages-sx" (String pages_sx));
|
||||||
(* Add CSS to hide island placeholder SX text until client hydrates *)
|
ignore (env_bind env "__shell-sx-css" (String sx_css));
|
||||||
let island_css = "[data-sx-island]{font-size:0;line-height:0;overflow:hidden;max-height:0}" in
|
|
||||||
ignore (env_bind env "__shell-sx-css" (String (sx_css ^ "\n" ^ island_css)));
|
|
||||||
ignore (env_bind env "__shell-sx-css-classes" (String ""));
|
ignore (env_bind env "__shell-sx-css-classes" (String ""));
|
||||||
ignore (env_bind env "__shell-asset-url" (String "/static"));
|
ignore (env_bind env "__shell-asset-url" (String "/static"));
|
||||||
ignore (env_bind env "__shell-sx-js-hash" (String sx_js_hash));
|
ignore (env_bind env "__shell-sx-js-hash" (String sx_js_hash));
|
||||||
|
|||||||
Reference in New Issue
Block a user