I see HMR and JS build tools. I understand that you're talking about hot-reloading your code to see changes in real time. I will take a moment to explain my thoughts on this.
If you take a little time to think about it, this is a really complicated problem.
Rust compiles to a native binary without a built-in runtime that manages modules or supports swapping code at runtime. While debug info exists, it’s not designed for safely swapping parts of a running program.
Not only that, changes in traits, function signatures or type definitions can significantly affect the generated machine code. This would have to immediately retrigger any static analysis as well as the recompilation of large parts of the crate and its dependents.
Compilation is also quite heavy, due to the amounts of static analysis required to make Rust as useful as it is. Also LLVM. This means that the naive approach of just recompiling the entire program on changes (even with incremental compilation enabled) may yield underwhelming results.
Note
If you would like to try that approach anyway (since it isn't particularly intrusive), check out cargo-watch. This can be used to recompile and rerun a binary on source changes.
Unfortunately, as a side effect it will also reset program state on reruns (obviously).
JavaScript and similar languages approach this differently. They run inside a long-lived runtime (like a browser or Node.js) that manages code as modules at runtime. This makes it possible to reload individual modules while the program is still running, often preserving application state. Because execution happens within this managed environment rather than as a standalone native binary, tooling can hook into the module system and swap code more easily.
The type systems are generally less strict and less coupled to code generation. Changes to source code don’t necessarily affect the program outside of nearby scope.
These languages are also built in a way that makes them compile very quickly. There isn't as much analysis involved in compilation, since a lot of the work is offloaded to runtime. What counts as a compilation unit is different as well, though here it depends on the tooling you use. Overall this means that small changes result in smaller units of work.
It is fairly easy to make a JS runtime hold additional information across reloads, since there is a long-lived runtime that can preserve state while you reload a single module. (Again, JS modules are a runtime concept, with enough information attached to them that it is relatively straightforward to swap out the code.) The persistent data allows you to come back to a previous state after reloading a module. This way you don't have to go through five menus just to get back to the button you're styling every time you change the color.
Rust doesn’t provide this kind of runtime or module system out of the box. Both languages serve different purposes and run in different environments. Rust supports use cases like embedded development, where resources are scarce and precise optimization as well as runtime predictability are crucial, while it is rather unlikely you would run into a JS powered car. At least I hope that future isn't coming.
I hope this gives you a clear picture of the kinds of problems such tooling has to overcome for it to be useful in this scenario. This may be helpful in choosing the right approach for your project.
Solutions you could consider:
- Using Tauri, which allows you to develop your Rust application with a web-stack based frontend. This way you can use
bun, node, deno etc. for the GUI part. There are some drawbacks though (primarily having to deal with IPC). I imagine this would be the most realistic solution for you.
- Using
subsecond as @kpreid mentioned. This allows you to keep everything in Rust, but it's an experimental solution that swaps out chunks of machine code at runtime. I wouldn't say its production ready, but it is a development tool, so if you're willing to adapt your code and workflow to it, it could help.
- You could implement something lighter on your own, for example run a QuickJS runtime inside your app and implement the GUI part there. Though that would involve a lot of setup on your part. You could also do the same with WebAssembly if you were to keep the frontend in Rust, but mind the compilation speed.