Dioxus:用一份 Rust 代码同时搞定 Web、桌面和移动端的全栈框架

你有没有过这种时刻 —— 产品同事扔过来一句”Web 版先上线,iOS 跟上,安卓月底交差,桌面客户端等融资进来再说”?你心里明白,所谓的” 跟上” 和” 等融资” 翻译成技术语言,就是三套 UI、两套 API、一份样式表,外加五种构建脚本。React Native 重写移动端、Electron 再造桌面端、Tauri 替换 Web 端,每一站都意味着招聘新人、改动状态管理、补贴新的调试技巧。

有没有可能只用一份 Rust 代码,就把 web、桌面、移动、服务端同时写完?

这是今天登顶 GitHub Trending 的 DioxusLabs/dioxus 想回答的问题。它在过去 24 小时新增 347 颗星,总计 36.7k Stars,license 是 MIT OR Apache-2.0 双授权,最新发布 v0.7.9(2026-05-08),距离 0.7 主版本只差几次 hot-patch 迭代。它的定位不是又一个 React 替代品,而是一套真正全栈的 Rust UI 框架 —— 前端、桌面、移动、SSR、服务端函数,全都靠一份代码、近乎一份心智模型完成。

项目背景:从 Electron 的” 包大、内存高” 出发

Dioxus 的第一次公开亮相要追溯到 2022 年,灵感来自它的同名前身 Dioxus 0.1:当 Electron 把 Chromium 揉进桌面应用,开发者开始意识到光是把”Web 应用装进 .dmg” 就要付 100MB+ 的体积溢价和几百兆常驻内存。当 Flutter 给出 Dart 的” 一份代码、三端一致”,Web 开发者又难以接受重写逻辑。当 Tauri 把 webview 抽离出来,又还要求你把 UI 用 HTML/JS 完整写一遍,再额外做 Rust 后端。

Dioxus 的核心立意是:React 风格的声明式 UI、Rust 的安全与速度、一份代码、三端渲染。开发者在 rsx! 宏里写 JSX 风格的标记,Dioxus 的虚拟 DOM 替你决定渲染目标 —— 浏览器里的 Wasm、桌面端的原生 webview、iOS/Android 的 WKWebView/ChromeView,或者直接走服务器端渲染 + hydration。

这意味着你不必为了打包桌面应用,重新实现一份 UI 树;也不必为了支持移动端,写两套 binding。

核心功能:六个点,看懂 Dioxus 在卷什么

1. 一份代码,四种渲染目标

dx serve 默认启动桌面平台,加 --platform web 就切换到浏览器,--platform ios --target aarch64-apple-ios 直接产出 .ipa,新增安卓支持同样是一个命令。底层由四个 renderer 抽象:

  • web-sys:编译成 Wasm,浏览器即目标,最小 hello world < 50KB
  • webview:macOS 用 WKWebView、Windows 用 WebView2、Linux 用 WebKitGTK,桌面二进制 < 5MB
  • Liveview:所有点击都走服务端,浏览器只负责渲染中间状态,对内网工具和数据看板极友好
  • WGPU 实验渲染:Dioxus 0.7 起正在尝试绕开 webview,直接用 GPU 绘图,目的是把移动端启动时间和包体积再砍一半

2. Signals:让” 状态即变量” 成为现实

Dioxus 的状态管理核心是 Signal<T>:一个会被自动追踪的 T,读取它的组件自动订阅,写它就精确触发依赖它的组件 re-render。这把 React 的 useState/Solid 的 createSignal/Svelte 的 $state 揉成了一个心智模型:

1
2
3
4
5
6
7
fn counter() -> Element {
let mut count = use_signal(|| 0);
rsx! {
button { onclick: move |_| count += 1, "Up high! {count}" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}

没有 useEffectuseMemouseReducer 的复杂度,订阅图由编译器在写时构造,运行时不付出任何 Virtual DOM diff 成本。

3. Subsecond 热重载

Dioxus 团队在 0.7 版本把 hotpatch 做成了” 次秒级 Rust 热补丁”。dx serve --hotpatch 监听 .rs 文件保存,自动重新编译并替换运行中进程的函数 —— 比 Cargo 的 cargo check 反馈循环快一个量级。改一个 CSS 颜色或者改一段 UI 文案,做一次 git stash 也来得及等编译。

4. Server Functions:Rust 写前后端,类型打通

得益于与 axum 的深度集成,Dioxus 提供 #[server] 宏把一个 Rust 函数直接变成 HTTP endpoint:

1
2
3
4
5
6
7
#[server]
async fn fetch_user(id: u64) -> Result<User, ServerFnError> {
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
.fetch_one(&*DATABASE.read().await)
.await?;
Ok(user)
}

客户端只需 fetch_user(42).await?,Dioxus 自动生成对应 fetcher,包括表单序列化、SSG/SSR 期间的直接调用、WebSocket 协议下的流式支持。前后端共享同一个类型,不再靠 OpenAPI/TypeScript 编译器当传话人。

5. 完整的 Web 框架能力,不只是”UI 库”

新版本默认集成了 WebSocket、SSE、流式响应、文件上传下载、表单、middleware、动态路由、静态站点生成、增量静态再生(ISR)。这是 Dioxus 与 Yew/Leptos 的最大差异 —— 后者是 UI 库,Dioxus 是完整的 Fullstack Framework

6. 一等公民的原生能力

桌面端可以直接调 Objective-C、Cocoa API;移动端直接调 JNI 和 Native API;Web 端调 Web-Sys。零 IPC 中转,意味着 Flutter 桥接常见的序列化和异步排队痛苦不存在。文件上传后用一台 iPad 拍照片、做 OCR、走本地数据库,全程没有 HTTP 跳转。

实战示例:五分钟写一个 “Todo + 桌面端打包”

第一步:安装 CLI

1
cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli --locked

或者用预编译版:

1
curl -L https://github.com/DioxusLabs/dioxus/releases/latest/download/dioxus-cli-installer.sh | sh

第二步:创建项目

1
2
3
dx new todo_app --template fullstack-web
cd todo_app
dx serve

立刻可以在浏览器打开本地 dev server。看到默认模板里的”Welcome to Dioxus”。

第三步:替换 main.rs

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
use dioxus::prelude::*;

#[derive(Clone, PartialEq, Debug)]
struct Todo { id: usize, text: String, done: bool }

#[component]
fn App() -> Element {
let mut todos = use_signal(Vec::<Todo>::new);
let mut draft = use_signal(String::new);

rsx! {
div { class: "p-6 max-w-md mx-auto font-sans",
h1 { class: "text-2xl mb-4", "Dioxus Todo Demo" }
div { class: "flex gap-2 mb-3",
input {
class: "border rounded px-2 py-1 flex-1",
value: "{draft}",
oninput: move |e| draft.set(e.value()),
}
button {
class: "bg-blue-500 text-white px-3 py-1 rounded",
onclick: move |_| {
if !draft.read().is_empty() {
todos.write().push(Todo {
id: todos.read().len(),
text: draft.read().clone(),
done: false,
});
draft.set(String::new());
}
},
"Add"
}
}
ul { class: "space-y-1",
for t in todos.read().iter() {
li { class: "flex items-center gap-2",
input {
r#type: "checkbox",
checked: t.done,
onchange: move |_| {},
}
span { "{t.text}" }
}
}
}
}
}
}

fn main() {
launch(App);
}

dx serve,浏览器看到的就是一份功能完整的待办清单 ——Tailwind 类名直接生效,因为 Dioxus 的 bundler 默认开启 Tailwind。

第四步:切桌面端打包

1
dx build --platform desktop --release

产物在 target/dx/todo_app/release/bundle/ 下,按平台分别产出 .app / .exe / .AppImage,体积 3-5MB。

加上 --platform ios--platform android 参数即可产出移动端包。

适用场景与限制

适合用 Dioxus 的场景

  • 跨平台工具型产品:必须给客户桌面端 + Web + 偶尔需要内嵌移动端的内部工具
  • AI Agent / CLI 的桌面外化:把 Python 服务包成桌面应用比 Python 写 Electron 体积小很多
  • 数字游民 / 独立开发者:不愿意分别维护 React + React Native + Electron 仓库
  • 静态站点 + 增量渲染:Hexo / Next 风格,但用 Rust 写,前后端共享类型
  • WGPU 实验渲染:对启动时间和包体积敏感、愿意接受新 renderer 边界的实验项目

现阶段需要小心的边界

  • 生态尚不及 Electron:大量专门为 Chromium 调好的 SaaS、监控 SDK,在 WebView 上偶有兼容性差异;Dioxus 团队在 Discord 上承认这是 WebView 路线最痛的痛点
  • 0.7 仍在打磨:v0.7.9 还是 pre-1.0,breaking change 时有发生;建议生产项目固定版本号 + 跟社区同频升级
  • WebView 性能上限:复杂的动画、桌面端同时打开三四十个窗口,仍不如纯原生 SwiftUI/UIKit 流畅
  • 与 Tauri 不冲突,但有重叠:Tauri 把 Rust 当 webview 后端、UI 用 JS;Dioxus 是把 UI 也交给 Rust—— 目标不同,按场景选

与同类框架的差异

维度 Dioxus Tauri Electron Flutter
语言 Rust Rust + JS JS/TS Dart
UI 风格 React-like HTML/JS(前端自选) HTML/JS 自有 widget
最小桌面体积 ~3MB ~3-10MB 100MB+ ~20MB
移动端 一等公民 实验 / 外部方案 一等公民
Server Functions 内建
学习曲线 React 经验迁移快 同时要懂前端 前端熟即可 新语言

Dioxus 想要吃的是” 我想用 Rust 写 UI,又能同时拿到 Web + 桌面 + 移动端” 这个交集。对那种只需 Web 或只需桌面的纯前端项目,Next.js/ Tauri 各有优势,不必硬上 Dioxus。

总结

Dioxus 把” 一份代码、三端渲染” 这件事在 Rust 生态里推到了一个新的可用水位。它不是第一个尝试这个方向的框架,但截至 0.7.9,它是第一个把 Server Functions、热重载、原生调用、跨平台打包整合得足够少坑的开源方案。对那些被”Web + 桌面 + 移动各一份仓库” 压到喘不过气的团队,它值得拿一个 1-2 周的内部工具项目做 PoC。

今天的 GitHub Trending 名单里,Dioxus 是少数几个既适合做严肃生产项目、又能动手玩起来的 Rust 框架 —— 比起纯研究项目(NVIDIA/Megatron-LM)和纯基础设施(trivy /airflow),它的回报曲线友好得多。

项目地址:https://github.com/DioxusLabs/dioxus
官网与文档:https://dioxuslabs.com
Discord 社区:https://discord.gg/XgGxMSkvUM