前言
Makepad 系列写完以后,有人问我:Rust 做客户端,除了 Makepad 还有什么值得看的?
我当时的回答是 Tauri 和 egui。但最近我重新看了 Dioxus------GitHub 36k star、v0.7 版本、一套代码跑 Web + 桌面 + 移动。
于是我决定开一个新系列。第一篇不写 API,先回答三个问题:Dioxus 是什么、它和已有的选择有什么本质区别、以及 10 分钟跑起来是什么体验。
1. Dioxus 在 Rust 生态里填了什么空缺
Rust 做 UI 应用,目前有四条成熟路线:
| 路线 | 代表框架 | UI 在哪写 | 适合 |
|---|---|---|---|
| WebView 壳 | Tauri | HTML/CSS/JS | 有前端团队、快速交付 |
| 即时模式 | egui | Rust | 工具面板、调试器 |
| 原生渲染 | Makepad | Rust DSL | 不考虑 WebView 的 Rust 原生 UI |
| 跨平台 WebView | Dioxus | Rust(rsx!) | 一套 Rust 代码跑 Web + 桌面 + 移动 |
Dioxus 的位置很微妙。它和 Tauri 一样用 WebView 做桌面渲染,但它不用 HTML/CSS/JS 写 UI------用 Rust 的 rsx! 宏。它和 Makepad 一样"UI 留在 Rust 里",但它选了 WebView 路线而不是原生渲染,所以生态和开发体验更像 Web 前端。
简单说:Dioxus 想做的是"用 Rust 替代 React"------同样的组件化心智、同样的声明式 UI、同样的 JSX-like 语法,但语言从 JavaScript 换成了 Rust。而且不只是 Web,桌面和移动也一起覆盖。
2. 和其他框架的直观对比
2.1 Dioxus vs Tauri
Tauri 的架构是"Rust 做后端能力 + 前端写 HTML/CSS/JS"。前端和 Rust 是两套代码,通信靠 IPC。
Dioxus 的架构是"Rust 写一切"。UI 在 rsx! 里写,逻辑在同一个 Rust 函数里写,没有跨语言边界。
如果你有现成的前端团队,Tauri 更快。如果你没有前端团队,或者想把整个应用留在 Rust 里,Dioxus 更自然。
2.2 Dioxus vs Makepad
这是两种路线。Makepad 用 GPU 着色器自己渲染界面,追求原生性能和动画能力。Dioxus 用系统 WebView 渲染,追求开发效率和跨平台一致性。
Makepad 的优势是渲染深度------着色器级别的动画、2D/3D 混合。Dioxus 的优势是宽度------Web、桌面、移动三端共用一套代码,而且 CSS 生态可以直接用。
我自己写完 Makepad 12 期之后,对这一点感受很深。Makepad 调一个布局要花很多心思,Dioxus 直接用 Tailwind CSS 就行------这是 WebView 路线最爽的地方。
2.3 Dioxus vs Leptos
这两个最像,都是 Rust 写的 Web 框架,都有 rsx! / view! 宏,都有 Server Functions。区别在于:
- Leptos 偏向"把 Web 做到极致"------细粒度响应式、SSR、hydration、streaming
- Dioxus 偏向"把跨平台做到极致"------同一套代码,换个编译目标就跑在桌面和移动上
选 Leptos 是因为你只想做 Web,但想做到最好。选 Dioxus 是因为你要跨端。
3. 10 分钟跑起来是什么体验
3.1 安装 CLI 和创建项目
Dioxus 有自己的 CLI 工具 dx,省了很多配置:
bash
# 安装 CLI
curl -fsSL https://dioxuslabs.com/install.sh | bash
# 创建项目
dx new my-app
cd my-app
# 跑起来
dx serve
dx serve 默认跑 Web 版,浏览器打开 http://localhost:8080。如果要跑桌面版:
bash
dx serve --platform desktop
项目结构:
text
my-app/
├── Dioxus.toml # Dioxus 项目配置
├── Cargo.toml
├── assets/ # 静态资源
│ └── main.css
└── src/
└── main.rs # 入口
和普通 Rust 项目比,多了一个 Dioxus.toml 用于配置平台特性和打包参数。dx CLI 内部调 cargo,所以 Cargo.toml 还是你熟悉的那个。
3.2 默认生成的项目长什么样
dx new 生成的 main.rs 是一个简单的计数器:
rust
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut count = use_signal(|| 0);
rsx! {
div {
h1 { "High-Five counter: {count}" }
button {
onclick: move |_| count += 1,
"Up high!"
}
button {
onclick: move |_| count -= 1,
"Down low!"
}
}
}
}
如果你写过 React,这段代码的语义一目了然:
use_signal相当于 React 的useState,但它是细粒度响应式的------只更新用到这个信号的那部分 DOMrsx!相当于 JSX,{count}是信号值的插值onclick是事件处理,直接写闭包
跟 React 的区别:这里没有虚拟 DOM diffing。count 变了,只更新 <h1> 标签里的文字,其他 DOM 节点不动。这是细粒度响应式的好处。
3.3 热更新:改代码立刻看到效果
dx serve 带了热更新。改一下 rsx! 里的文字,浏览器自动刷新。CSS 也是热更的,改 assets/main.css 立刻生效。
Rust 代码的热更有实验性支持:dx serve --hotpatch。但不是所有改动都能热更------只限于函数体和闭包内的改动。改结构体定义、加新依赖、改 Cargo.toml 需要重新编译。
这个体验和 trunk serve(Yew)或 cargo leptos watch(Leptos)类似,比 Makepad 的 cargo run 快一个档次------至少 CSS 和标记不用重新编译。
3.4 同个项目跑桌面版
在同一个项目里,不改一行代码:
bash
dx serve --platform desktop
弹出来的是系统 WebView 渲染的窗口,内容和 Web 版完全一致。样式、交互、逻辑------全部复用。
再跑移动版:
bash
dx serve --platform android
需要 Android SDK 和模拟器,但代码同样不改。
这就是 Dioxus 最核心的卖点:一套业务逻辑 + 一套 UI 代码,三个编译目标。
4. 坦诚说现在的问题
写到这里,必须泼点冷水。
Dioxus 的桌面端目前基于 WebView 渲染。和 Tauri 一样,你的应用跑在系统的浏览器引擎里。窗口控制、系统菜单、文件对话框这些原生能力要靠 Dioxus 的 desktop 模块提供------覆盖不如 Tauri 全,但够用。
移动端更是如此。Android 和 iOS 能跑,但触控体验、性能调优、应用商店合规------这些离"生产级"还有距离。
WGPU 渲染器(不用 WebView,直接 GPU 渲染)是实验性的,不建议在生产项目里用。
但如果你现在的目标是:做一个内部工具,或者一个 MVP,Web 版先上线,桌面版后面跟上------Dioxus 的"一套代码多端跑"会让你省很多事。
5. 这个系列准备怎么写
和 Makepad 系列一样,不讲"翻译官方文档"。每期解决一个明确问题,带可运行代码,带真实踩坑。
大概的路线:
- 第 1 期(就是这篇):为什么是 Dioxus + 10 分钟上手
- 第 2 期:
rsx!语法深度拆解------和 JSX 一样不一样的地方 - 第 3 期:Signals 和响应式状态管理
- 后面:组件通信、路由、桌面端、Server Functions、实战项目、打包部署
如果你从 React 背景过来,这个系列会让你很快上手。如果你从 Makepad 系列过来的------你会发现 Dioxus 的开发体验完全不同,更像写前端,但语言是 Rust。
总结
Dioxus 在 Rust 生态里占了一个独特的位置:用 Rust 替代 React,一套代码跑三端。
它不是最好的 Web 框架(Leptos 在 Web 上更深),也不是最好的桌面框架(Tauri 更成熟)。但如果你需要"跨端 + Rust 单一语言栈",Dioxus 是目前最接近这个目标的选择。
下一期拆 rsx! 语法:条件渲染、列表渲染、属性绑定------哪些跟 JSX 一样,哪些完全不一样。
你用过 Dioxus 吗?或者在做 Rust 跨平台选型?评论区聊聊你的场景。