Rust in Everything
基于 dioxus 0.7.10

SSR 与 fullstack

这一部分讲首屏主线和调用主线在服务端的那一半,以及它们在浏览器里怎么接上。源码分在四个 crate:dioxus-ssr(packages/ssr/src,不到一千行,只管把 VNode 树写成 HTML)、dioxus-server(目录是 packages/fullstack-server,axum 路由、渲染池、流式、增量缓存)、dioxus-fullstack-core(水合数据的格式、use_server_future、FullstackContext、ServerFnError)、dioxus-fullstack(server function 的客户端和编码)。浏览器那一侧的水合代码在 dioxus-web 的 hydration/ 和 interpreter 的 ts/hydrate.ts、ts/initialize_streaming.ts。

一次页面请求已经把首屏主线从头到尾串过一遍,这一部分逐层展开:前三章是不流式时的首屏(默认 StreamingMode::Disabled),后三章是 server function、流式和缓存。

  1. dioxus-ssr:每个模板只切一次字符串段(StringCache),渲染时按段写、动态部分逐个填;pre_render 加的三种标记(data-node-hydration、<!--node-idN-->…<!--#-->、<!--placeholderN-->)各补的是浏览器解析 HTML 时丢掉的哪种信息;文本、属性、script / style 里的转义规则;留给流式渲染的组件回调。
  2. 一次请求的渲染:launch、serve、router 造出的 axum 路由(server function、带 hash 的静态文件永久缓存、fallback);SsrRendererPool::render_to 逐步;本地线程池有几个线程、渲染里阻塞会挡住谁;状态码和响应头从哪来、什么时候就改不了了;出错时渲染器不回池。
  3. 水合:服务端每个 scope 一份 HydrationContext,按深度优先合并成按位置排列的槽位,CBOR 再 base64;客户端在同一个顺序里取回;两边 hook 顺序不一致时,类型不同会让整页水合失败,类型相同则静默串值;debug 调试数组为什么对不上。
  4. server function:#[get] / #[post] / #[server] 两边各生成什么,参数和返回值怎么编码,ServerFnError 和状态码。
  5. 流式渲染:OutOfOrder 模式下先发占位、后发替换块和这一块的水合数据。
  6. 增量渲染与配置:ServeConfig、index.html 模板、增量缓存。
flowchart TB
  req["GET 页面"] --> pipeline["render_to 渲染池"]
  pipeline --> vdom["每请求一个 VirtualDom"]
  vdom --> ssr["dioxus-ssr 写 HTML"]
  vdom --> hdata["收集水合数据"]
  ssr --> html["带标记的 HTML"]
  hdata --> html
  html --> client["浏览器 rebuild"]
  client --> claim["rehydrate 认领节点"]
  sf["server function"] --> vdom
  sf --> client
  stream["流式 替换块"] --> claim

VirtualDom 本身怎么建树、怎么等 suspense,见 03 VirtualDom 内核;服务端那个 axum::Router 在 axum 一侧的结构,见 axum 卷的 dioxus 生成的 Router。

💬 关联讨论

发起讨论
加载中...