summaryrefslogtreecommitdiff
path: root/bs5/server/Claude.md
blob: cbf70d7c7b9bbf81f340d3de5cc714d38a957a5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

Core Architecture

  server.re - Main entry point:
  - Uses Dream web framework (OCaml's web server)
  - Sets up routing with getAndPost helper for progressive enhancement
  - Serves static assets (CSS, JS) and handles React rendering

  Key Libraries (from dune file):

  - dream - Web framework
  - react/reactDOM - Native React implementation
  - demo_shared_native - Shared components
  - lwt.unix - Async I/O
  - yojson - JSON handling

  Rendering Pipeline

  Three rendering modes:
  1. renderToString - Basic SSR (line 28-31)
  2. renderToStaticMarkup - No hydration attributes (line 34-38)
  3. renderToStream - Streaming SSR with React Server Components

  React Server Components (RSC)

  DreamRSC.re handles the magic:

  Content negotiation:
  switch (Dream.header(request, "Accept")) {
  | Some(accept) when is_react_component_header(accept) =>
    stream_model(~location=Dream.target(request), app)  (* RSC payload *)
  | _ =>
    stream_html(~bootstrapScripts, app)  (* Full HTML *)

  Server Actions (lines 50-87):
  - Reads ACTION_ID header
  - Decodes form data or request body
  - Calls registered server function via FunctionReferences.get
  - Streams response back as application/react.action

  Request Flow

  1. Client request → Dream router
  2. Accept header check → RSC payload vs HTML
  3. Server function lookup → FunctionReferences registry
  4. Component rendering → ReactServerDOM.render_model/render_html
  5. Streaming response → Chunks sent via Dream.write

  File Structure in OCaml syntax:

  (* Main server setup *)
  let server =
    Dream.logger (
      Dream.router [
        get_and_post "/" Pages.Home.handler;
        Dream.get "/static/**" (Dream.static "./build/client");
        (* ... more routes *)
      ]
    )

  (* Page handler example *)
  let handler _request =
    let app = Document.make [
      Html.h1 [React.string "Hello"]
    ] in
    Dream.html (ReactDOM.renderToStaticMarkup app)

  The beauty is it's a standard Dream web server that happens to render React components natively, with RSC streaming as an enhancement
  layer on top!