Rust in Everything
基于 dioxus 0.7.10

源码地图

主线位置:不在主线上。本页说明三条主线经过的代码分在哪些 package、哪些文件,package 之间怎么依赖,门面 crate dioxus 怎么把它们按 feature 拼起来。

dioxus 仓库在 tag v0.7.10 的根 Cargo.toml 是一个工作区,cargo metadata --no-deps 列出 112 个成员:

类别个数位置
库和工具57packages/ 下 56 个,加上根目录的 dioxus-examples
CLI 测试用的小工程19packages/cli-harnesses/*
Playwright 端到端测试工程18packages/playwright-tests/*
完整示例15examples/01-app-demos、07-fullstack、10-integrations
subsecond 的测试工程3packages/subsecond/subsecond-tests/*

[workspace.package] 的 version = "0.7.10",绝大多数 package 用 version.workspace = true,所以一起发版。例外是 const-serialize 和 const-serialize-macro(0.8.0-alpha.0)、manganis-core-07(0.7.2)。下文只讲那 57 个库和工具,按层分成七组。

本卷涉及的 package 之间是这样依赖的(只画 [dependencies] 里的 dioxus 系 crate,省略 core-types、cli-config、devtools 这类小工具 crate):

flowchart TB
  facade["dioxus 门面"] --> web["dioxus-web"]
  facade --> server["dioxus-server"]
  facade --> fs["dioxus-fullstack"]
  facade --> router["dioxus-router"]
  facade --> hooks["dioxus-hooks"]
  server --> ssr["dioxus-ssr"]
  server --> fscore["dioxus-fullstack-core"]
  server --> router
  fs --> fscore
  fs --> fsmacro["dioxus-fullstack-macro"]
  web --> interp["dioxus-interpreter-js"]
  web -.->|"hydrate"| fscore
  web --> html["dioxus-html"]
  router --> html
  html --> hooks
  hooks --> signals["dioxus-signals"]
  fscore --> signals
  signals --> core["dioxus-core"]
  ssr --> core
  interp --> core
  core --> gbox["generational-box"]
  signals --> gbox
  html --> cmacro["dioxus-core-macro"]
  cmacro --> rsx["dioxus-rsx"]

几条值得记住的依赖关系:

  • dioxus-core 不依赖任何渲染器、也不依赖 signals。 它的 dioxus 系依赖只有 dioxus-core-types、generational-box,外加热补丁用的 subsecond。ReactiveContext 在 core 里,Signal 在上一层的 dioxus-signals 里:core 只知道「有个上下文被标脏了」,不知道是谁标的。
  • dioxus-ssr 只依赖 dioxus-core 和 dioxus-core-types。 服务端渲染 HTML 不需要 dioxus-html:元素名、属性名都已经在 Template 里,是字符串。
  • dioxus-rsx 不依赖 dioxus 的任何 crate。 它是 rsx! 的解析和代码生成库(syn / quote),dioxus-core-macro 是包装它的过程宏 crate;dioxus-autofmt(dx fmt)和 dioxus-rsx-hotreload 也复用它。
  • dioxus-server 依赖 dioxus-router。 依赖挂在它默认打开的 router feature 上(带 router 的 streaming feature),ssr.rs 用 ParseRouteError 认出「路由不匹配」,把响应状态码改成 404。
  • dioxus-web 只在 hydrate feature 下依赖 dioxus-fullstack-core(虚线),而且依赖时写死了 features = ["web"];dioxus-server 依赖它时写死了 features = ["server"]。所以 fullstack-core 里的 #[cfg(feature = "web")] 和 #[cfg(feature = "server")] 是由「哪个渲染器把它拉进来」决定的,见怎么读这一卷。

仓库里有一份 notes/architecture/00-OVERVIEW.md(2025-12-29 加入,开头说是写给「future Claude agents (and human contributors)」的),里面有一棵 crate 树。那棵树是按主题分的,不是依赖图:它把 dioxus-autofmt 画在 dioxus-rsx 下面,实际是 autofmt 依赖 rsx;它列的 dioxus-cli-opt 在这个 tag 的 packages/ 里不存在。本页的依赖以各 Cargo.toml 为准。

行数是 find <dir>/src -name '*.rs' -print0 | xargs -0 cat | wc -l 在 tag 解包上的结果,不含 tests/、benches/ 和示例。

核心:组件、模板与 VirtualDom

packagesrc/ 行数管什么入口和主要文件(行数)讲它的部分
dioxus-core10 678VirtualDom、Runtime、scope、调度、diff、Mutations、事件、suspense 与错误边界virtual_dom.rs 808、nodes.rs 1 152(VNode、Template、DynamicNode)、diff/ 1 767、runtime.rs 654、events.rs 677、suspense/ 841、mutations.rs 423、scope_context.rs 417、reactive_context.rs 413、tasks.rs 405、scheduler.rs 289、scope_arena.rs 14203 VirtualDom 内核、Template 与 VNode
dioxus-rsx5 515rsx! 的解析和代码生成(不是过程宏 crate)rsx_call.rs(CallBody)、template_body.rs 420(TemplateBody,生成 Template)、attribute.rs 917、element.rs 736、component.rs 534、ifmt.rs 419("{x}" 格式化字符串)rsx! 展开成什么
dioxus-core-macro2 665过程宏:rsx!、#[component]、#[derive(Props)]lib.rs 42(rsx 转给 dioxus-rsx)、props/mod.rs 1 845、component.rs 664#[component] 与 Props
dioxus-core-types170core 和渲染器共用的小类型:事件是否冒泡(bubbles.rs)、格式化bubbles.rs 105事件
dioxus-html10 962HTML / SVG 元素和属性的定义、事件数据类型(MouseData、FormData……),大部分是宏生成的表attribute_groups.rs 2 516、elements.rs 2 168、events/事件委托

dioxus-core 的 src/lib.rs 把二十几个模块都声明成私有(mod virtual_dom;),再 pub use 出需要的类型;另有一个 #[doc(hidden)] pub mod internal,放的是只给 rsx! 展开后的代码用的热重载类型。所以文档里看到的 dioxus_core::VirtualDom、dioxus_core::Element 看不出在哪个文件;Element 就定义在 lib.rs 里,是 Result<VNode, RenderError>。

响应式:signal、hooks 与 store

packagesrc/ 行数管什么主要文件(行数)讲它的部分
generational-box1 847让句柄能 Copy 的存储:Owner 持有值,GenerationalBox 是「指针 + 代数」lib.rs 450(GenerationalBox、Owner)、unsync.rs 392、sync.rs 396、error.rs 166generational-box
dioxus-signals4 287Signal、Memo、ReadSignal、GlobalSignal,读写 traitsignal.rs 550(Signal)、read.rs 534、write.rs 766、memo.rs 274、global/ 373、copy_value.rs 210Signal、Memo 与 effect、context 与全局 signal
dioxus-hooks2 104use_signal、use_memo、use_effect、use_resource、use_future、use_coroutine、use_context、use_actionuse_resource.rs 559、use_action.rs 336、use_future.rs 198、use_reactive.rs 143、use_coroutine.rs 14104 响应式
dioxus-stores2 9450.7 新增的 Store:按字段、按元素订阅subscriptions.rs 501、store.rs 449、impls/ 1 749(Vec、HashMap、Option、Result……)Store
dioxus-stores-macro1 077#[derive(Store)]、#[store]derive.rs 616Store

use_signal 本身只有几行(use_signal 在 hooks/src/use_signal.rs 里),Signal 的机制全在 dioxus-signals 和 generational-box 里。

渲染器:web、SSR 和其他

packagesrc/ 行数管什么主要文件(行数)讲它的部分
dioxus-web4 247浏览器里的 wasm 渲染器:主循环、WebsysDom、事件转换、水合、history、documentlib.rs 266(run 主循环)、dom.rs 186、mutations.rs 262、events/ 1 634、hydration/ 418、history.rs 408、document.rs 303、devtools.rs 35805 浏览器渲染、水合
dioxus-interpreter-js464 行 Rust + 1 693 行 TypeScript在 JS 侧执行 DOM 指令的解释器;unified_bindings.rs 用 sledgehammer_bindgen 生成批量调用的绑定unified_bindings.rs 210、ts/core.ts 325、ts/hydrate.ts、ts/initialize_streaming.ts;src/js/*.js 是编译好的单行产物,提交在仓库里WebsysDom 与 interpreter、事件委托
dioxus-ssr922把 VirtualDom 渲染成 HTML 字符串,可带水合标记renderer.rs 513(Renderer)、cache.rs 372、lib.rs 35(render、pre_render)dioxus-ssr
dioxus-desktop、dioxus-native、dioxus-native-dom、dioxus-liveview5 527 / 674 / 924 / 1 797桌面和移动(wry webview)、原生渲染(blitz)、liveview(WebSocket 把指令推给浏览器)本卷不讲—

dioxus-ssr 的 src/ 里还有 template.rs 和 config.rs 两个文件,内容只有一个换行;lib.rs 仍然声明了 pub mod config;、pub mod template;,所以 dioxus_ssr::config、dioxus_ssr::template 是两个空模块。dioxus-html 被 web、desktop、native 共用,SSR 不用它。

fullstack:server function、水合与服务端

packagesrc/ 行数管什么主要文件(行数)讲它的部分
dioxus-fullstack6 225用户直接用的那一层:server function 的客户端请求、按类型选编码、各种载荷client.rs 693(ClientRequest)、magic.rs 852(ServerFnEncoder / ServerFnDecoder)、encoding.rs 120、payloads/ 3 956(WebSocket、流、SSE、文件、表单、msgpack……)server function
dioxus-fullstack-core2 245客户端和服务端共用的类型:水合数据、use_server_future、ServerFnError、流式状态transport.rs 530(HydrationContext)、loader.rs 381、streaming.rs 338、error.rs 314、httperror.rs 217、history.rs 146、server_future.rs 139水合、流式渲染
dioxus-fullstack-macro1 925#[server]、#[get]、#[post] 等宏,一个文件lib.rs 1 925server function
dioxus-server(目录 packages/fullstack-server)3 171axum 集成:路由、SSR 渲染池、流式、增量缓存、启动ssr.rs 767(SsrRendererPool)、server.rs 493(DioxusRouterExt、FullstackState)、config.rs 307(ServeConfig)、launch.rs 290(router、serve)、isrg/ 632、document.rs 166、streaming.rs 162、serverfn.rs(ServerFunction)一次请求的渲染、增量渲染与配置

dioxus-fullstack 的 src/ 里有 63% 是 payloads/:除了默认的 JSON,server function 还能收发流、SSE、WebSocket、文件和表单,这些载荷各自实现客户端和服务端两边的编码。本卷只讲默认路径,载荷只列不展开。

router

packagesrc/ 行数管什么主要文件(行数)讲它的部分
dioxus-router2 741Router、Outlet、Link 组件,RouterContext,Routable traitroutable.rs 965、contexts/ 581(router.rs 420)、components/ 662(link.rs 266)、navigation.rs 170Router 运行时
dioxus-router-macro2 682#[derive(Routable)]:路由树、FromStr、Displaylib.rs 791、route_tree.rs 614、route.rs 469、segment.rs 338、query.rs 174Routable

document 与 history

packagesrc/ 行数管什么主要文件(行数)讲它的部分
dioxus-document1 045Title、Meta、Link、Script、Style 组件和 eval;Document trait 由各平台实现document.rs 152、eval.rs 82、elements/document 与 eval
dioxus-history381History trait 和 MemoryHistorylib.rs 261、memory.rs 120Router 运行时

这两个 crate 都只是 trait 加默认实现。浏览器里的实现在 dioxus-web 的 document.rs 和 history.rs,服务端的 ServerDocument 在 dioxus-server 的 document.rs,服务端的路由历史在 dioxus-fullstack-core 的 history.rs。

工具链:CLI、热重载、资源、代码分割

packagesrc/ 行数管什么
dioxus-cli(dx)40 833构建、打包、开发服务器、热重载,是 dioxus-core 的 3.8 倍;本卷只用它编实验,不讲源码
dioxus-cli-config336CLI 通过环境变量传给应用的配置:服务地址、base_path、构建 id
subsecond、subsecond-types959 / 92Rust 代码的热补丁:跳转表替换函数,VirtualDom 在 debug 下注册回调
dioxus-devtools、dioxus-devtools-types220 / 56开发服务器和应用之间的消息(模板替换、补丁)
dioxus-rsx-hotreload1 079比较新旧 rsx!,算出能热替换的模板
dioxus-autofmt2 225dx fmt,基于 dioxus-rsx
dioxus-rsx-rosetta162HTML 转 rsx
manganis、manganis-core、manganis-macro、manganis-core-07620 / 2 005 / 1 910 / 723asset!():编译期把资源描述写进二进制的链接段,CLI 处理后回填最终 URL
const-serialize、const-serialize-macro2 264 / 234编译期序列化,asset! 用
dioxus-asset-resolver583运行时按 URL 找资源
wasm-splitter、wasm-split-macro、wasm-split-cli、wasm-used214 / 226 / 1 725 / 346wasm 代码分割
lazy-js-bundle194构建脚本里把 TypeScript 编成 JS(interpreter 用)
dioxus-logger116默认的 tracing 订阅者,logger feature 打开时 launch 会初始化它
dioxus-config-macro、dioxus-config-macros38 / 39前者是 server_only!、web! 这类按 feature 展开的过程宏;后者是 router 宏内部用的 maybe_wasm_split!
其他dioxus-cli-telemetry、dioxus-dx-wire-format、depinfo、dioxus-component-manifest、dioxus-html-internal-macro、dioxus-ext(publish = false)

热重载怎么接进运行时,本卷只讲两个接口:hot-patch 之后的 SchedulerMsg::AllDirty,和 debug 构建里 rsx! 从一个 GlobalSignal 读模板,见怎么读这一卷的 debug 一节。asset! 在本站怎么用,见 10 在本站中。

门面 crate dioxus

packages/dioxus/src 只有两个文件:lib.rs 251 行、launch.rs 373 行。它不实现任何东西,只做三件事:

  1. 按 feature 重新导出子 crate。 lib.rs 里每个 pub use 前面都有一个 #[cfg(feature = "...")]:

    feature导出
    总是dioxus::core(dioxus_core)、dioxus::subsecond、dioxus::config_macros
    signalsdioxus::signals、dioxus::stores
    hooks / html / documentdioxus::hooks / dioxus::html / dioxus::document、dioxus::history
    web / ssr / router / fullstackdioxus::web / dioxus::ssr / dioxus::router / dioxus::fullstack
    serverdioxus::server(dioxus_server)和 dioxus::serve
    desktop、mobile、native、liveview各自的渲染器 crate
  2. 拼一个 prelude。 use dioxus::prelude::* 带进来的东西也按 feature 分:macro 给 rsx!、component、Props;hooks 和 signals 给全部 hooks 和 signal 类型;fullstack 给 server、get、post 等宏和 use_server_future、ServerFnError;server 给 serve、DioxusRouterExt、ServeConfig;router 给 Router、Link、Outlet、Routable、navigator。不受 feature 控制的是从 dioxus_core 直接拿的一组:VirtualDom、Element、VNode、spawn、use_hook、provide_context、consume_context、ErrorBoundary、SuspenseBoundary 等。

  3. launch。 launch.rs 的 LaunchBuilder 按打开的平台 feature 选一个启动函数,见怎么读这一卷。

dioxus 的默认 feature 是 launch、devtools、logger、lib,lib 又展开成 macro、html、signals、hooks、mounted、document、asset、warnings、cli-config。router、fullstack、web、server 都不在默认集里,要自己开。

小结

  • 工作区 112 个成员,其中库和工具 57 个,整体同版本 0.7.10 发布。
  • 运行时从下往上:generational-box → dioxus-core → dioxus-signals → dioxus-hooks → dioxus-html;rsx! 在 dioxus-rsx 里实现、由 dioxus-core-macro 包成过程宏。
  • 渲染器只依赖 core:dioxus-ssr 连 dioxus-html 都不需要;dioxus-web 加上 dioxus-interpreter-js(TypeScript 解释器 + sledgehammer 绑定)。
  • fullstack 分四个 crate:用户面 dioxus-fullstack、两边共用的 dioxus-fullstack-core、宏 dioxus-fullstack-macro、axum 集成 dioxus-server;fullstack-core 的 web / server feature 由拉它进来的渲染器写死。
  • dioxus-cli 一个 package 就有 4 万行,是 dioxus-core 的 3.8 倍;本卷不讲它。
  • 门面 crate dioxus 只做重新导出、prelude 和 launch,导出什么全看 feature。

💬 关联讨论

发起讨论
加载中...