一年的狄奥克修斯在生产:好,痛苦
在本页(5节)
经过一年的狄奥克斯·富士达克的制作,Rust代码是我最无聊的生意。 CI是最激动人心的部分,不尽人意:一个发布架构在GitHub托管的跑者身上需要90分钟。
那一年我从上次工作开始,继续用我自己的产品。 回到4月,我写了为什么我选了Rust来生产一个微型SaaS。 短版本:开始较慢,较后期生活更便宜。 这个帖子是账单。
我所追求的
SeggWat是SaaS产品的一个内应用反馈工具。 它的仪表板是一个Dioxus 0.7 fullstack app into a Cargo 工作空间:一个具有服务器功能的后端箱子,一个认证箱,以及大约10个UI的箱子,包括洞察力,反馈,想法,板子,部件和设置。 十二箱靠二氧化物维生。 所有东西都放在PostgreSQL上。
下面的页面建在同一堆上。
“Fullstack”是指一个Rust codebase从事三项工作。 它在服务器上制作,将服务器功能作为后端运行,并将客户端编译到WebAssembly,使页面变得交互。
好东西
一个语言,一直下去
数据库查询,业务规则,服务器功能,按钮:全部Rust. 一个工具链一个物料一套习惯当东西断裂时一个地方看
直到你成为独唱创始人,我没有一个“前端大脑”和“后端大脑”,我打开工作空间继续走
两边都一样
这是我最想念的。
一个结构得到定义一次。 数据库层返回它,服务器函数发送它,组件使其产生它。 当我重命名一个字段时,货物检查会给我一份包括UI在内的每个破碎地点的清单。 没有OpenAPI的光谱可以再生,也没有TypeScript接口与后端同步漂移。
胜利并没有更快地写出代码。 却无人审查。
其他平台的门仍开着
狄奥克斯可以从同一个组件模型中瞄准桌面和移动,包括iOS. 我的产品今天都不需要本地的应用软件但当我决定把一年的工作放在哪里时,知道我可以不重写地运送一个。
制作很无聊
这就是重点所在。 一旦编译出来,它大多只是运行。 整类的“ 未定义不是函数” 错误从没有到达用户,因此确实通过错误是逻辑错误。 我宁愿把注意力花在那里。
4月份的“生产中的麻烦”论点与真正的用户保持了联系。
痛苦
编译时间
这是路斯特福音者倾向于跳过的部分。
仪表板会编译两次:一次是给服务器的,一次是给浏览器的hem32. 一打Dioxus的箱子加上一个宏重的UI加起来。 在本地,我的工作流程文件中的评论就像日记一样:
- 单是WASM就花了22分钟在6个核心上。 这是一个单一的叶子箱:为浏览器编译的仪表板。
- 发布图像需要大约90分钟在GitHub主持双核跑者。 以我个人的VPS选手来说
- Clippy被OOM杀死了 7GB主机跑车上的货运剪辑器 -- -- 工作空间 -- -- 所有目标因退出码143而死亡,根本没有诊断。 修补是10GB的互换文件加上CARGO BUILD JOBS=1来剪切峰值内存。 我的灯关需要交换。
在某个时候,我停止了在每次推向主线上建立图像。 他们现在利用发行标签或者当我用手触发它们时因为每次推90分钟的计费票是花钱的傻方法
我试过的
- 用斯瓦蒂内姆/破伤风卡切但有一个陷阱。 一个工作流程运行只能从自己的ref或默认分支中恢复缓存,GitHub驱逐了7天未使用的缓存。 一旦我停止主建,释放结构开始冷。 我的工作几乎很有趣:在依赖性崩溃之后,我手动触发一个主线的积木,只是为了保持缓存的温暖。
- 建造和测试一个去,所以测试再利用编译了文物,而不是第二次编译世界。
- 模具连结器不错,但联系从来不是瓶颈。 编曲是。
- 重楼的自营跑者这是迄今为止最大的胜利,90分钟降到40分钟。 这也意味着我现在维持一个构建服务器。
每一个都有帮助。 它们都没有改变基本的数学:两个编译目标,一个大依赖树和许多宏意味着很多编译。
"全Rust"带有星号
业务逻辑都是Rust. 情况并非如此。
SeggWat的见解页面显示图表,因此图是Chart.js,从一个CDN装入,包裹在约340行的JavaScript中,Dioxus通过二oxus-use-js调用。 Styling是Tailwind,因此CI也安装了Bun,并在Rust甚至开始前运行Tailwind CLI.
我不介意,这是务实的。 如果你选择Dioxus来逃离JavaScript,就知道自己要签什么:Rust
我会再来一次吗?
人们问道:“什么能帮助我最快的航行?” 更好的问题是,“什么能帮助我保持不恨我的生活?”
对于后端来说,答案仍然是Rust
我改变主意了。 如果我在建立真正类似应用的东西,但我建造的大多是仪表板:表格、表格、几张图表和几张图。 我对每次放行都要缴纳22分钟的瓦斯M税
接下来是什么:Topcoat
因此,我的下一个项目是使用Topcoat,一个新的满层框架从tokio -rs org,宣布在7月。
这让狄奥克斯的赌注相反服务器上的一切,组件都是可以直接查询数据库的Async函数。 对于交互,您会用普通的,按类型检查的 Rust 来写 $(...) 表达式。 Topcoat在服务器上评价它们进行第一个渲染,同时也将其翻译为JavaScript,所以它们在浏览器中即时重新运行。 没有WASM捆绑,也没有第二个编译目标。
自动同步
以Topcoat README为例。
在纸面上,Topcoat保留了我对Dioxus的热爱(一种语言,共享类型,没有API层),并删除最伤害的部分,即22分钟的WASM构建。
说清楚,这是赌注,不是结果。 Topcoat的README称其为早期和实验性,我放弃多平台选项。 我还没有衡量任何一座建筑。
我将用真实的数字来写后续:编译时间、CI分钟,若我的释放时间从40分钟降至10分钟,如果不是这样,你也会听到这一点。
我是Hauke。 我用Rust在SeggWat、Stepshot和以下网页上写作
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
One year of Dioxus fullstack in production: the good, the painful
On this page (5 sections)
After a year of Dioxus fullstack in production, the Rust code is the most boring part of my business. CI is the most exciting part, and not in a good way: a release build takes 90 minutes on a GitHub-hosted runner.
That year started at my previous job and continued on my own products. Back in April I wrote about why I picked Rust for a production micro SaaS. The short version: slower at the start, cheaper to live with later. This post is the bill.
What I’m running
SeggWat is an in-app feedback tool for SaaS products. Its dashboard is a Dioxus 0.7 fullstack app inside a Cargo workspace: a backend crate with server functions, an auth crate, and about ten UI crates covering insights, feedback, ideas, boards, widgets and settings. Twelve crates depend on dioxus. Everything sits on PostgreSQL.
infra.page is built on the same stack.
“Fullstack” means one Rust codebase doing three jobs. It renders on the server, runs server functions as the backend, and compiles the client to WebAssembly so the page becomes interactive.
The good
One language, all the way down
Database query, business rule, server function, button: all Rust. One toolchain, one formatter, one set of habits, one place to look when something breaks.
That sounds minor until you’re a solo founder juggling several products. I don’t have a “frontend brain” and a “backend brain” that each need warming up. I open the workspace and keep going.
The same types on both sides
This is the one I’d miss most.
A struct gets defined once. The database layer returns it, the server function sends it, and the component renders it. When I rename a field, cargo check gives me a list of every place that broke, including the UI. There’s no OpenAPI spec to regenerate and no TypeScript interface drifting out of sync with the backend.
The win isn’t writing code faster. It’s refactoring without fear, late at night, with nobody to review it.
The door to other platforms stays open
Dioxus can target desktop and mobile, including iOS, from the same component model. None of my products needs a native app today. But knowing I could ship one without a rewrite mattered when I decided where to put a year of work.
Production is boring
That’s the whole point. Once it compiles, it mostly just runs. A whole class of “undefined is not a function” bugs never reaches users, so the bugs that do get through are logic bugs. That’s where I’d rather spend my attention anyway.
The “boring in production” argument from April survived contact with real users.
The painful
Compile times
This is the part Rust evangelists tend to skip.
The dashboard compiles twice: once for the server and once to wasm32 for the browser. A dozen Dioxus crates plus a macro-heavy UI add up. Locally it’s tolerable on a decent machine. CI is a different story, and the comments in my workflow files read like a diary of it:
- The WASM build alone takes about 22 minutes on 6 cores. That’s a single leaf crate: the dashboard compiled for the browser.
- A release image takes about 90 minutes on a GitHub-hosted 2-core runner. On my own VPS runner it’s around 40, and that’s the good version.
- Clippy got OOM-killed. cargo clippy --workspace --all-targets on the 7 GB hosted runner died with exit code 143 and no diagnostics at all. The fix was a 10 GB swapfile plus CARGO_BUILD_JOBS=1 to cut peak memory. My linter needs swap.
At some point I stopped building images on every push to main. They now build on release tags or when I trigger them by hand, because 90 billed minutes per push is a silly way to spend money.
What I tried
- Caching with Swatinem/rust-cache. It helps, but there’s a trap. A workflow run can only restore caches from its own ref or the default branch, and GitHub evicts caches unused for 7 days. Once I stopped building on main, release builds kept starting cold. My workaround is almost funny: after a dependency bump, I manually trigger a build on main just to keep the cache warm.
- Building and testing in one go, so the tests reuse compiled artifacts instead of compiling the world a second time.
- The mold linker. Nice, but linking was never the bottleneck. Compiling was.
- A self-hosted runner for the heavy builds. This was by far the biggest win, 90 minutes down to 40. It also means I now maintain a build server.
Every one of these helped. None of them changed the underlying math: two compile targets, a big dependency tree and lots of macros means a lot of compiling.
“All Rust” comes with an asterisk
The business logic is all Rust. The edges aren’t.
SeggWat’s insights page shows charts, and I couldn’t find a Rust charting library I’d trust in production. So the charts are Chart.js, loaded from a CDN and wrapped in about 340 lines of JavaScript that Dioxus calls through dioxus-use-js. Styling is Tailwind, so CI also installs Bun and runs the Tailwind CLI before Rust even starts.
I’m fine with that. It’s pragmatic. But if you’re choosing Dioxus specifically to escape JavaScript, know what you’re signing up for: Rust, plus some JS glue, plus a JS toolchain in your pipeline.
Would I do it again?
People ask, “What helps me ship fastest?” The better question is, “What helps me keep shipping without hating my life?”
For the backend, the answer is still Rust, and it isn’t close.
For the frontend, I’ve changed my mind a bit. If I were building something truly app-like, with heavy client state, offline support or a real mobile app, I’d pick Dioxus again. But most of what I build is dashboards: forms, tables, a few charts and some toggles. For that, I’m paying a 22-minute WASM tax on every release for interactivity I barely use.
What’s next: Topcoat
So my next project is going to use Topcoat, a new fullstack framework from the tokio-rs org, announced in July.
It makes the opposite bet from Dioxus. Everything renders on the server, and components are async functions that can query the database directly. For interactivity, you write $(...) expressions in ordinary, type-checked Rust. Topcoat evaluates them on the server for the first render and also translates them to JavaScript, so they re-run instantly in the browser. There’s no WASM bundle and no second compile target.
async
Example from the Topcoat README.
On paper, Topcoat keeps what I love about Dioxus (one language, shared types, no API layer) and removes the part that hurts most, the 22-minute WASM build.
To be clear, this is a bet, not a result. Topcoat’s README calls it early-stage and experimental, with breaking changes expected. I’m giving up the multi-platform option. And I haven’t measured a single build yet.
I’ll write the follow-up with real numbers: compile times, CI minutes, and whatever I end up missing from Dioxus. If my release build drops from 40 minutes to 10, you’ll hear about it. If it doesn’t, you’ll hear about that too.
I’m Hauke. I build SeggWat, Stepshots and infra.page in Rust and write about it on OXIDT.
Auto-fetched and translated by AI Atlas. All rights belong to the original author.