Releases: DioxusLabs/dioxus
v0.5.1: Bug fixes!
0.5.1: Bug Fixes!
Thanks everyone for the great feedback for the 0.5.0 launch! We're releasing 0.5.1 now with a bunch of bug fixes.
This includes some stuff like fixing async polling, some smalls issues with memos and resources, and a memory leak in EventHandler.
We strongly recommend you upgrade your dioxus project with cargo update
!
The autoformatter also changed a bit, so if you're using the VSCode extension, you should get the updates automatically.
What's Changed
- fix: remove misplaced 'a' from cli help text by @simonsan in #2166
- fix(generational-box): polished README.md by @Andrew15-5 in #2168
- fix: Hide launch mod when disabled by @marc2332 in #2171
- fix: Reflect that
create
command was renamed tonew
by @foresterre in #2174 - Fix: Move dioxus_core::diff::node logs from info to trace by @marko-lazic in #2182
- Bump rfd to version 0.14 fixing 2149 by @davidMcneil in #2161
- Fix the mobile feature on the dioxus crate by @ealmloff in #2185
- Fix hydration for static text nodes at the root of the template by @ealmloff in #2184
- Fix child routers with the web history by @ealmloff in #2172
- Make Leptos iteration example equivalent of Dioxus iteration example by @gbj in #2191
- docs: 📝 new readme translated into Turkish by @Tahinli in #2196
- fix: typo by @loverdos in #2202
- Fix for Counters sample code in README by @ekanna in #2209
- chore: Clean up
use_on_destroy
docs by @marc2332 in #2199 - Fix for Counters sample code in Readme by @ekanna in #2213
- Fix typo is style tag removal causing style attributes to not be removed by @jkelleyrtp in #2220
- Fix rendering aborted nodes in SSR by @ealmloff in #2218
- Fix and test spawn_forever by @ealmloff in #2216
- Reuse placeholder nodes on each thread to reduce allocation by @ealmloff in #2217
- Re-export generational box error types from the signals crate by @ealmloff in #2212
- Fix firefox refreshing loop in debug mode by @ealmloff in #2214
- Implement the "Toggle Developer Tools" menu item in desktop by @mullr in #2198
- Fixes to autofmt, make it more aggressive by @jkelleyrtp in #2230
- Fix hydration for non-bubbling events by @ealmloff in #2234
- Fix: requeue events, process events by @jkelleyrtp in #2236
- Feat: provide root context as method on virtualdom by @jkelleyrtp in #2243
- Fix: memory leak on listeners for elements by @jkelleyrtp in #2244
- Fix memory leak in owner by @jkelleyrtp in #2245
- Use a VecDequeue instead of a vec for bytes by @jkelleyrtp in #2246
- Fix recycling on component callbacks by @jkelleyrtp in #2247
New Contributors
- @simonsan made their first contribution in #2166
- @foresterre made their first contribution in #2174
- @marko-lazic made their first contribution in #2182
- @davidMcneil made their first contribution in #2161
- @gbj made their first contribution in #2191
- @loverdos made their first contribution in #2202
- @ekanna made their first contribution in #2209
- @mullr made their first contribution in #2198
Full Changelog: v0.5.0...v0.5.1
v0.5.0
Dioxus 0.5: Signal Rewrite, Remove lifetimes/unsafe, CSS Hotreloading, 5x Faster Desktop, Asset System, and more!
Read the Full 0.5 release post on the Dioxus blog
The story
Here at Dioxus Labs, we have an unofficial rule: only one rewrite per year.
Our last rewrite brought some amazing features: templates, hotreloading, and insane performance. However, don’t be mistaken, rewrites are scary, time consuming, and a huge gamble. We started this new rewrite on January 1st of 2024, completed it by Feburary 1st, and then spent another month and a half writing tests, squashing bugs, and polishing documentation. Rewrites are absolutely not for the faint of heart.
If you’re new here, Dioxus (dye•ox•us) is a library for building GUIs in Rust. Originally, I built Dioxus as a rewrite of Yew with the intention of supporting proper server-side-rendering. Eventually, Dioxus got popular, we got some amazing sponsors, and I went full time. We’ve grown from a team of 1 (me) to a team of 4(!) - pulled entirely from the wonderful dioxus community.
Now, Dioxus is something a little different. Real life, actual companies are shipping web apps, desktop apps, and mobile apps with Dioxus. What was once just a fun little side project powers a small fraction of apps out in the wild. We now have lofty goals of simplifying the entire app development ecosystem. Web, Desktop, Mobile, all end-to-end typesafe, blazing fast, living under one codebase. The dream!
With 0.5 we took a hard look at how Dioxus would need to change to achieve those goals. The request we got from the community was clear: make it simpler, make it robust, make it polished.
What’s new?
This is probably the biggest release of Dioxus ever, with so many new features, bug fixes, and improvements that I can’t list them all. We churned over 100,000 lines of code (yes, 100,000+) with over 1,400 commits between 0.4.3 and 0.5.0. Here’s a quick overview:
- Complete rewrite of
dioxus-core
, removing all unsafe code - Abandoning
use_state
anduse_ref
for a clone-freeSignal
-based API - Removal of all lifetimes and the
cx: Scope
state - A single, unified
launch
function that starts your app for any platform - Asset hotreloading that supports Tailwind and Vanilla CSS
- Rewrite of events, allowing access to the native
WebSys
event types - Extension of components with element properties (IE a Link now takes all of
<a/>
properties) - Integrated Error Boundaries and Server Futures with Suspense integration
- 5x faster desktop reconciliation and custom asset handlers for streaming bytes
- Streaming server functions and fullstack hotreloading
- Tons of QoL improvements, bug fixes, and more!
Lifetime Problems
To make Dioxus simpler, we wanted to remove lifetimes entirely. Newcomers to rust are easily scared off by lifetime issues, and even experienced Rustaceans find wading through obtuse error messages exhausting.
In dioxus 0.1-0.4, every value in a component lives for a 'bump
lifetime. This lifetime lets you easily use hooks, props and the scope within event listeners without cloning anything. It was the chief innovation that made Dioxus so much easier to use than Yew when it was released.
// Scope and Element have the lifetime 'bump
fn OldDioxusComponent(cx: Scope) -> Element {
// hook has the lifetime 'bump
let mut state = use_state(cx, || 0);
cx.render(rsx! {
button {
// The closure has the lifetime 'bump which means you don't
// need to clone hook before you move it into the closure
onclick: move |_event| *state += 1,
}
})
}
This works great for hooks most of the time. The lifetime lets you omit a bunch of manual clones every time you want to use a value inside an EventHandler (onclick, oninput, etc).
However, the lifetime doesn’t work for futures. Futures in dioxus need to be 'static
which means you always need to clone values before you use them in the future. Since a future might need to run while the component is rendering, it can’t share the component’s lifetime.
// Scope and Element have the lifetime 'bump
fn OldDioxusComponent(cx: Scope) -> Element {
// state has the lifetime 'bump
let state = use_state(cx, || 0);
cx.spawn({
// Because state has the lifetime 'bump, we need to clone it to make it
// 'static before we move it into the 'static future
let state = state.clone();
async move {
println!("{state}");
}
});
// ...
}
If you don’t clone the value, you will run into an error like this:
4 | fn OldDioxusComponent(cx: Scope) -> Element {
| --
| |
| `cx` is a reference that is only valid in the function body
| has type `&'1 Scoped<'1>`
...
8 | / cx.spawn(async move {
9 | | println!("{state}");
10 | | });
| | ^
| | |
| |______`cx` escapes the function body here
| argument requires that `'1` must outlive `'static`
The error complains that cx
must outlive 'static
without mentioning the hook at all which can be very confusing.
Dioxus 0.5 fixes this issue by first removing scopes and the 'bump
lifetime and then introducing a new Copy
state management solution called signals. Here is what the component looks like in dioxus 0.5:
// Element has no lifetime, and you don't need a Scope
fn NewComponent() -> Element {
// state is 'static and Copy, even if the inner value you store is not Copy
let mut state = use_signal(|| 0);
// State is already 'static and Copy, so it is copied into the future automatically
spawn(async move {
println!("{state}");
});
rsx! {
button {
// The closure has the lifetime 'static, but state is copy so you don't need to clone into the closure
onclick: move |_event| state += 1,
}
}
}
While this might seem like a rather innocuous change, it has an impressively huge impact on how easy it is to write new components. I’d say building a new Dioxus app is about 2-5x easier with this change alone.
Goodbye scopes and lifetimes!
In the new version of dioxus, scopes and the 'bump
lifetime have been removed! This makes declaring a component and using runtime functions within that component much easier:
You can now declare a component by just accepting your props directly instead of a scope parameter
#[component]
fn MyComponent(name: String) -> Element {
rsx! { "Hello {name}!" }
}
And inside that component, you can use runtime functions directly
spawn(async move {
tokio::time::sleep(Duration::from_millis(100)).await;
// You can even use runtime functions inside futures and event handlers!
let context: i32 = consume_context();
});
Now that lifetimes are gone, Element
s are 'static
which means you can use them in hooks or even provide them through the context API. This makes some APIs like virtual lists in dioxus significantly easier. We expect more interesting APIs to emerge from the community now that you don’t need to be a Rust wizard to implement things like virtualization and offscreen rendering.
Removal of all Unsafe in Core
Removing the 'bump
lifetime along with the scope gave us a chance to remove a lot of unsafe from dioxus. dioxus-core 0.5 contains no unsafe code 🎉
There’s still a tiny bit of unsafe floating around various dependencies that we plan to remove throughout the 0.5 release cycle, but way less: all quite simple to cut or unfortunately necessary due to FFI.
Signals!
Dioxus 0.5 introduces Signals as the core state primitive for components. Signals have two key advantages over the existing use_state
and use_ref
hooks: They are always Copy
and they don’t require manual subscriptions.
Copy state
Signal<T>
is Copy
, even if the inner T
values is not. This is enabled by our new generational-box crate (implemented with zero unsafe). Signals can even optionally be Send+Sync
if you need to move them between threads, removing the need for a whole class of specialized state management solutions.
The combination of Copy + Send + Sync
Signals, and static components makes it incredibly easy to move state to anywhere you need it:
fn Parent() -> Element {
// We use a sync signal here so that we can use it in other threads,
// but you could use a normal signal if you have !Send data
let mut state = use_signal_sync(|| 0);
spawn(async move {
// Signals have a ton of helper methods that make them easy to work with.
// You can call a signal like a function to get the current value
let value: i32 = state();
});
// Because signals can be sync, we can copy them into threads easily
std::thread::spawn(move || {
loop {
std::thread::sleep(Duration::from_millis(100));
println!("{state}");
}
});
render! {
button {
// You can easily move it into an event handler just like use_state
onclick: move |_| state += 1
}
}
}
With Copy
state, we’ve essentially bolted on a light form of garbage collection into Rust that uses component lifecycles as the triggers for dropping state. From a memory perspective, this is basically the same as 0.4, but with the added benefit of...
v0.5.0-alpha.0: first prerelease
First prerelease of dioxus
v0.5 is coming soon! We've decided to start putting out pre-releases so developers on the "bleeding-edge" have a stable checkpoint to use as we release new breaking features.
The full release notes for 0.5 are here:
Migration guide:
https://ealmloff.github.io/docsite/learn/0.4/migration/
Feel free to hop into the discord to give feedback and/or chat about the new changes.
Full Changelog: v0.4.3...v0.5.0-alpha.0
v0.4.3
v0.4.3
This is the last release of the 0.4 cycle, containing a number of useful new features as well as many bug fixes.
You can now manipulate the dioxus runtime without going through the Scope
object.
This was originally released many months ago, but we never made the release post.
What's Changed
- Update all uncommented commands to remove actions-rs by @esimkowitz in #1366
- Add ScopeId::ROOT by @JaniM in #1398
- Explain features necessary for the
pre_cache_static_routes
function. by @photon-garden in #1401 - Expose new_in_scope for signals by @ealmloff in #1384
- Make incremental a cfg feature. by @skabber in #1409
- Fix cli compile error due to tauri bundler adding fields by @fanyang89 in #1416
- Add query segment example and documentation by @Stygmates in #1417
- fix: Typo on use_on_unmount by @marc2332 in #1421
- Improve CLI docs by @tigerros in #1404
- fix: prettier_build unavailabe by @mrxiaozhuox in #1410
- fix: Add the --locked param to every cli installation command by @marc2332 in #1427
- Pin Tauri dependencies to a minor version by @ealmloff in #1415
- Forward Wry's devtools, dox and linux-body flags by @ealmloff in #1412
- Only collect the rsx and render macros in autofmt by @ealmloff in #1420
- Bump the dioxus-cli to 0.4.1 by @ealmloff in #1424
- Find attributes and components to drop when rendering any lazy nodes by @ealmloff in #1376
- Add initial_value to textarea by @valyagolev in #1434
- Url decode routes by @ealmloff in #1407
- Bump actions/checkout from 3 to 4 by @dependabot in #1452
- Remove stray log statement in
onmounted
by @oxkitsune in #1453 Routable
improvements by @tigerros in #1461- Use a
gen
inPartialEq
forUseSharedState
by @DanielAlbl in #1389 - Switch to tracing for logging by @ealmloff in #1436
- Add system for creating component attributes + new
#[component]
attribute by @tigerros in #1448 - Fix use_future docs by @ealmloff in #1440
- fix: Update doc links from v0.3 to v0.4 by @marc2332 in #1464
- Fix docs.rs build for desktop by @ealmloff in #1382
- Deduplicate serve code with hot reloading in the CLI crate by @ealmloff in #1446
- Fix web query segments by @ealmloff in #1406
- Handle oninput for select elements by @ealmloff in #1315
- Fix leaked signals created in effects by @ealmloff in #1386
- Fix parsing spread routes by @ealmloff in #1298
- Fix events with a text node target by @ealmloff in #1322
- Expose public methods for manipulating the global runtime by @ealmloff in #1441
- Return more useful messages when a server function errors by @ealmloff in #1313
- Fix boolean attribute rendering in SSR by @ealmloff in #1324
- Update Cargo.toml (desktop package) by @Deepp0925 in #1466
- Fix #1367 by @tigerros in #1471
- PartialOrd for UseState by @Calastrophe in #1473
- Make RuntimeGuard public by @ealmloff in #1467
- Restore the tray feature in the desktop crate by @ealmloff in #1475
- Fix playwright tests on windows by @ealmloff in #1480
- fix: Update server function docs link by @marc2332 in #1489
- liveview: Add `interpreter_glue_relative_uri by @kang-sw in #1481
- Rename
dioxus-hooks
modules to use snake_case by @tigerros in #1498 - feat: initial_selected attribute for options by @White-Oak in #1508
- Update
dioxus-core-macro
README as per #1448 by @tigerros in #1510 - cli: Fix typo,
resouces
by @srid in #1516 - chore:
tauri-mobile
->cargo-mobile2
by @amrbashir in #1518 - Add
use_on_mount
and fix some typos by @tigerros in #1497 - CLI: Clarify where serve warnings come from by @tigerros in #1524
- Fix clippy from 248d78f by @tigerros in #1532
- cli: Log connection errors during
dx serve
in desktop apps by @srid in #1515 - cli: Add ability for autofmt to read stdin by @mertzt89 in #1529
- feat: Remove unused deps by @marc2332 in #1447
- CLI: Remove redundant directories by @tigerros in #1535
- Include README and Dioxus logo in package docs by @tigerros in #1536
- feat: initial_checked attribute for inputs by @White-Oak in #1540
- Fix deref for mapped Write structs in dioxus-signals by @esimkowitz in #1549
- Make signal callable on stable by @ealmloff in #1550
- Add must use to several hooks by @ealmloff in #1544
- Change the semantics of exprs/for loops allocations strategy by @jkelleyrtp in #1546
- refactor todo mvc example by @alexanderjophus in #1556
- Add openidconnect authentication demo by @Stygmates in #1500
- feat: Optional web support for hot-reload crate by @marc2332 in #1527
- Add link to website section on contributing to root README by @tigerros in #1559
- Append prop documentation to function when using
#[inline_props]
or#[component]
by @tigerros in #1563 - Improve prop docs by @tigerros in #1565
- Fix using signals outside of a scope by @ealmloff in #1551
- Add error message when overlapping fullstack features are enabled by @ealmloff in #1570
- Add an readable error when you name a prop key by @ealmloff in #1558
- Add Newtype so that Rust-url can be IntoRoutable by @andar1an in #1579
- Fix prop docs line breaks by @tigerros in #1573
- Implement LiveView Router Integration by @DonAlonzo in #1505
- Silence desktop build outputs from cargo by @hirschenberger in #1584
- Make window invisible until the first render by @HKalbasi in #1588
- Bump actions/setup-node from 3 to 4 by @dependabot in #1592
- Fix
#[component]
expansion Clippy warning by @tigerros in #1599 - Fix the scroll event on the web renderer by @ealmloff in #1602
- fix: Read value from root when calling
AtomState::current()
by @marc2332 in #1609 - fix syntax error at
#[derive(Props)]
using const generics by @syrflover in #1607 - fix: Update error message when no atom root is found in context by @marc2332 in #1611
- update readme by @xTekC in #1615
- Drop any attribute after rendering by @ealmloff in #1581
- Updated server_fn to 0.5.2 by @WolfeCub in #1620
- Fix 1623 by @tigerros in #1626
- fix keyboard input on calc example by @alexanderjophus in #1639
- Related to #1547: use
dioxus-cli
within a workspace (wildcard-members, real package names) by @RGafiyatullin in #1642 - Fix tailwind.css 404 in Cli web platform build by @hjin-me in #1649
- Fix grammar typo in comment by @onichandame in ...
v0.4.2
What's Changed
- Reject all external routes when parsing a route by @ealmloff in #1272
- Fix navigator push/replace route by @ealmloff in #1274
- Deduplicate route history by @ealmloff in #1273
- Update scroll history lazily when you leave a page by @ealmloff in #1275
- Release new versions (0.4.1) by @jkelleyrtp in #1276
- fixed "http_equiv" in meta to generate "http-equiv" instead of "http_… by @ChrisCA in #1277
- Fix Fullstack docs building by @ealmloff in #1284
- Make server function features flexible by @ealmloff in #1285
- doc: fix typo by @eventualbuddha in #1287
- docs(cli): fix typo by @eventualbuddha in #1294
- build(web): fix
default-features
warning by @eventualbuddha in #1296 - Minor Proxy Improvements by @eventualbuddha in #1289
- docs(hooks): fix typos by @eventualbuddha in #1299
- refactor(cli): move
check
module alongside others by @eventualbuddha in #1304 - docs(cli): update subcommand comments by @eventualbuddha in #1303
- chore(cli): remove unused module by @eventualbuddha in #1302
- fix(cli): prevent "zip slip" vulnerability in tool extract by @eventualbuddha in #1305
- incorrect word spelling by @dylanblokhuis in #1308
- chore(cli): remove unused function by @eventualbuddha in #1301
- refactor(cli): use more semantic
Instant::elapsed
by @eventualbuddha in #1307 - fix: readme awesome link by @HashCookie in #1320
- Set response headers from response, not request, parts by @gmorenz in #1328
- docs: add Japanese README by @eltociear in #1329
- Make launch functions pub by @CodedNil in #1288
- Separate Parent and Child Component Lifetimes by @ealmloff in #1332
- Fix the login form example by @ealmloff in #1327
- Complete Signals implementation by @ealmloff in #1300
- Update tailwind examples to work with multi-page apps by @swpecht in #1339
- Use
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in #1344 - Add 'with' and 'with_mut' to 'use_shared_state' by @DanielAlbl in #1353
- Publish CLI binaries for cargo-binstall by @esimkowitz in #1358
- Fix the context API in lists by @ealmloff in #1351
- Fix leak in core because of bump allocated Vec by @ealmloff in #1364
- Update README.md to use 0.4 version of
Guide
instead of 0.3 by @Dillon-Roller in #1370 - DOC: Add note about form prevent_default behavior. by @vgobbo in #1343
- CLI: Behavior when web.https.mkcert is not specified. by @vgobbo in #1342
- FileEngine: expose native file types on different platforms by @wooden-worm in #1258
- deps: Update keyboard-types to 0.7. by @waywardmonkeys in #1378
- Update ZH_CN.md to use 0.4 version of guide by @HashCookie in #1388
- Constrain Props lifetime to parent, not child scope lifetime by @ealmloff in #1345
New Contributors
- @ChrisCA made their first contribution in #1277
- @dylanblokhuis made their first contribution in #1308
- @HashCookie made their first contribution in #1320
- @gmorenz made their first contribution in #1328
- @eltociear made their first contribution in #1329
- @CodedNil made their first contribution in #1288
- @swpecht made their first contribution in #1339
- @Dillon-Roller made their first contribution in #1370
- @vgobbo made their first contribution in #1343
- @wooden-worm made their first contribution in #1258
- @waywardmonkeys made their first contribution in #1378
Full Changelog: v0.4.0...v0.4.2
v0.4.1
What's Changed
- docs(cli): fix typo by @eventualbuddha in #1294
- refactor(cli): move
check
module alongside others by @eventualbuddha in #1304 - docs(cli): update subcommand comments by @eventualbuddha in #1303
- chore(cli): remove unused module by @eventualbuddha in #1302
- fix(cli): prevent "zip slip" vulnerability in tool extract by @eventualbuddha in #1305
- incorrect word spelling by @dylanblokhuis in #1308
- chore(cli): remove unused function by @eventualbuddha in #1301
- refactor(cli): use more semantic
Instant::elapsed
by @eventualbuddha in #1307 - Use
--profile
to identify cargo build artifact if present for dx cli web builds by @swpecht in #1344 - Publish CLI binaries for cargo-binstall by @esimkowitz in #1358
- CLI: Behavior when web.https.mkcert is not specified. by @vgobbo in #1342
- Fix cli compile error due to tauri bundler adding fields by @fanyang89 in #1416
- Improve CLI docs by @tigerros in #1404
- fix: Add the --locked param to every cli installation command by @marc2332 in #1427
- Bump the dioxus-cli to 0.4.1 by @ealmloff in #1424
v0.4.0
Dioxus 0.4 Github
The Dioxus 0.4 release includes 6 new crates, a ton of new features and a plethora of bug fixes!
Highlights:
- Rewritten Type safe Router
- Fullstack cross-platform meta framework
- Suspense
- CLI Linting
- CLI Bundling
- Rewritten Documentation
- Cross platform system API wrappers: Dioxus STD
Router
The router has been revamped for the 0.4 release. The router now uses an enum to define routes. If you use this enum to link to a page, the compiler will insure you never link to a page that doesn’t exist. The new router also includes Nesting, Layout, and sitemap support:
use dioxus::prelude::*;
use dioxus_router::prelude::*;
#[derive(Routable, Clone)]
enum Route {
#[route("/")]
Home {},
#[route("/blog")]
Blog {},
}
fn App(cx: Scope) -> Element {
render! {
Router::<Route> {}
}
}
#[inline_props]
fn Home(cx: Scope) -> Element {
render! {
Link {
to: Route::Blog {},
"Go to the blog"
}
h1 { "Welcome to the Dioxus Blog!" }
}
}
#[inline_props]
fn Blog(cx: Scope) -> Element {
render! {
Link {
to: Route::Home {},
"Go to the home page"
}
h1 { "Blog" }
}
}
Huge shoutout to @TeFiLeDo for creating many different prototypes and tests for the new router!
Fullstack
The 0.4 release introduces the Fullstack crate. The fullstack crate contains adapters for communicating with your
Fullstack Rendering
The fullstack crate makes it dead simple to create a server side rendered hydrated app with fullstack typesafety. The fullstack crate lets you render your page on the server on every request (or incrementally) and then hydrate it on the client.
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
}
}
Fullstack communication
In addition to fullstack rendering, the new fullstack create allows you to communicate with your server effortlessly. You can annotate a function with #[server]
to make the code inside the function only run on the server. This makes it easy to build a backend for your web or desktop application!
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut count = use_state(cx, || 0);
render! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
button {
onclick: move |_| {
to_owned![count];
async move {
let double = double(*count).await.unwrap();
count.set(double);
}
}
}
}
}
#[server]
async fn double(number: usize) -> Result<usize, ServerFnError> {
// This will *only* run on the server
Ok(number * 2)
}
Suspense
0.4 adds the long awaited suspense feature. This allows you to wait for a future on the server and then send the result to the client. You can combine suspense with server functions to wait for some code on your server to finish running before rendering a component:
use dioxus::prelude::*;
use dioxus_fullstack::prelude::*;
fn main() {
LaunchBuilder::new(app).launch();
}
fn app(cx: Scope) -> Element {
let mut server_data = use_server_future(cx, || get_server_data())?;
render! {
div {
"{server_data:?}"
}
}
}
#[server]
async fn get_server_data() -> Result<usize, ServerFnError> {
Ok(42)
}
CLI Improvements
The Dioxus CLI has moved into the dioxus main repo
The Dioxus CLI is now called dx
instead of dioxus
. The 0.4 release of the Dioxus CLI added three main features:
Dioxus Check
@eventualbuddha has done a fantastic job creating a new Dioxus check command to lint your Dioxus code for errors! It will warn you if your code violates the rules of hooks
dx check
Dioxus Bundle
The Dioxus CLI can now create installers for MacOs and Windows powered by tauri-bundle!
dioxus bundle
Desktop Hot Reload
In Dioxus 0.4, rsx hot reloading has moved from the hot reload macro to the CLI for desktop, liveview, fullstack, and TUI applications. Now every platform can use the CLI to start hot reloading:
dioxus serve --platform desktop --hot-reload
Mobile
Dioxus now has improved mobile support with a getting started guide and a mobile example!
Documentation
The documentation has been revamped for the 0.4 release. We now have a short getting started guide that teaches you how to build a hackernews clone in Dioxus.
The new documentation site takes full advantage of the fullstack crate to prerender the pages.
While working on the new docsite we also created two new crates:
- Dioxus Mdbook makes it easy to use markdown into your Dioxus components and use Dioxus components in your markdown
- Dioxus Search makes it easy to create instant search indexes for your Dioxus page's. It integrates with the Dioxus router's new site map feature to automatically detect searchable pages
Together these crates allow us to make our documentation fully interactive and instantly searchable. The new documentation site contains live code snippets of different components as you walk through the guide.
Dioxus STD
One of the biggest problems with cross platform development in rust today is finding ergonomic ways to interact with system APIs. @doge and @marc have created a new Dioxus std create that makes it easy to interact with a variety of system APIs in Dioxus across all platforms. It contains helpers for Geolocation, clipboard access, notifications, color schemes, translation, and more!
Async Eval
@doge has made the use_eval hook significantly more powerful for the 0.4 release of Dioxus. You can now send messages to and from Javascript asynchronously. This feature makes it possible to listen for Javascript events that Dioxus doesn’t officially support (for example the intersection observer API).
Dioxus HTML
The 0.4 release introduces file upload support for the dioxus-html crate. This makes it easy to upload files to you desktop, liveview, or web application.
This release also introduces a new onmounted event that provides access to some common node APIs like focusing an element or getting the size of an element in a cross platform way.
Rink and Blitz-core
Dioxus' TUI renderer Rink and WGPU renderer Blitz can now be used without Dioxus. This makes it possible to render your own html into either of these renderers or use these renderers in your own framework. To get started, see the Blitz and Rink framework-less examples.
Community
Office Hours
Dioxus now holds weekly office hours in the discord! If you are interested in the project, need help with your projects, or want to get started contributing, you should come to our weekly office hours!
The office hours happen every Friday at 9:00 AM (PDT) in the Dioxus discord server
Recordings of office hours are available on the Dioxus youtube channel
New contributors
There have been almost 50 new contributors since the 0.3 release!
@mirkootter, @davidpdrsn, @mwcz, @askreet, @marcerhans, @ndarilek, @arniu, @pickfire, @arqalite, @ProfXwing, @Icekey, @willothy, @rtwfroody, @attilio, @stephenandary, @Rigellute, @onweru, @Byron, @nicoburns, @serzhiio, @indiv0, @azriel91, @elliotwaite, @nmlt, @nicholastmosher, @TimothyStiles, @jpearnshaw, @jmsfltchr, @striezel, @echochamber, @xinglixing, @sean, @torsteingrindvik, @vanhouc, @terhechte, @traxys, @Mouradost, @DianQK, @eventualbuddha, @leahiel, @kaid, @frisoft, @Niedzwiedzw
Conclusion
For more information on the 0.4 release and all the new features that have been introduced, read the blogpost
Full Changelog: v0.3.2...v0.4.0
v0.3.2
Dioxus 0.3 is bringing a lot of fantastic new features:
- Massive performance improvements
- Hot reloading for web and desktop
- Autoformatting for RSX via dioxus fmt
- New LiveView renderer
- Input widgets for TUI
- Lua plugin system for CLI and overhaul of CLI
- Multi window desktop apps and direct access to Tao/Wry
- General improvements to RSX (if chains, for loops, boolean attributes, any values)
- Rusty event types with support for complex techniques like file uploading
- Skia renderer and WGPU renderer
- Chinese and Portuguese translations
- A new landing page
For more details about each of these new improvements see the release blog post
v0.2.4
Releasing Diouxs v0.2.4
This update is just a minor bump to Dioxus. A ton of bugs were fixed, and a few new features were added.
Notably
- Option in props are now optional by default
- Active_class for Links
- Improve rsx! errors
- Fix some bugs in hydration
- Introduce a very young version of Liveview
- Introduce a very young version of Dioxus Native (just the core bits)
- use_eval for running JS
A bunch of bugs were fixed too!
Overall, this release will improve the stability, performance, and usability of Dioxus without any major breaking changes.
What's Changed
- Added active class to router link by @maccesch in #294
- active_class prop for Router by @maccesch in #309
- fix: Filter prevent default for buttons in Dioxus Desktop by @jkelleyrtp in #310
- Remove release_max_level features from several Cargo.toml log dependencies by @naturalethic in #314
- Update setup.md by @imbolc in #323
- Improve
rsx!
errors by @overlisted in #322 - Option<...> props are optional by default. by @maccesch in #315
- Capture correct radio button value in a form input event by @naturalethic in #320
- fix: setnode method for rehydration code by @jkelleyrtp in #316
#[inline_props]
generics by @overlisted in #324- tui bugfixes and text modifier elements by @Demonthos in #302
- fix: instantly resolving futures should not use popping by @jkelleyrtp in #330
- Convert all logs to trace by @naturalethic in #334
- Fix form value collecting from form element instead of input element by @naturalethic in #333
- Fixed Docs Problem by @mrxiaozhuox in #336
- Minor improvements to the guide by @kdwarn in #335
- fix: diff_lazynodes bug adding children by @Demonthos in #331
- Eval stuff by @overlisted in #318
- Include optional public-url flag in build instruction within getting … by @TimboTambo in #343
- Fix typo in docs for NodeFactory.bump by @autarch in #350
- fix: inline props should look for attributes by @jkelleyrtp in #347
- Update mobile.md by @erlend-sh in #349
- Fixed example by @mrxiaozhuox in #356
- Fixed Document by @mrxiaozhuox in #357
- feat: allow customizing the index and head by @jkelleyrtp in #353
- Fix query parsing by @MiriChan in #358
- feat: Add a use_state equivalent for Fermi by @jkelleyrtp in #341
- Removed alerts when right click is disabled. by @blemelin in #363
- Add PartialEq to events::KeyCode by @freopen in #365
- add benchmark, headless mode, and shutdown context to tui by @Demonthos in #362
- Liveview Axum Integration + Example updates by @WIGGLES-dev in #366
- fix: unmarking component as dirty in silent write by @koptan in #378
- fix: export useeffect in hooks module by @koptan in #379
- Remove
cli
docs by @mrxiaozhuox in #380 - FEAT: Allow starting live view apps with props by @WIGGLES-dev in #377
- Fix cfg conditions for wasm by @DusterTheFirst in #382
- Convert web_sys Events to html Data by @oovm in #240
- change with_ctrl_c_quit to without_ctrl_c_quit for tui config by @Demonthos in #388
- Tui Lazy Attributes and Layout by @Demonthos in #329
New Contributors
- @maccesch made their first contribution in #294
- @naturalethic made their first contribution in #314
- @imbolc made their first contribution in #323
- @Demonthos made their first contribution in #302
- @kdwarn made their first contribution in #335
- @TimboTambo made their first contribution in #343
- @erlend-sh made their first contribution in #349
- @MiriChan made their first contribution in #358
- @freopen made their first contribution in #365
- @WIGGLES-dev made their first contribution in #366
- @koptan made their first contribution in #378
- @DusterTheFirst made their first contribution in #382
Full Changelog: v0.2.0...v0.2.4
v0.2.0
Dioxus v0.2 Release: TUI, Router, Fermi, and Tooling
March 9, 2022
Thanks to these amazing folks for their financial support on OpenCollective:
Thanks to these amazing folks for their code contributions:
Just over two months in, and we already a ton of awesome changes to Dioxus!
Dioxus is a recently-released library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more. Dioxus looks and feels just like React, so if you know React, then you'll feel right at home.
fn app(cx: Scope) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
h1 { "Count: {count}" }
button { onclick: move |_| count += 1, "+" }
button { onclick: move |_| count -= 1, "-" }
})
}
What's new?
A ton of stuff happened in this release; 550+ commits, 23 contributors, 2 minor releases, and 6 backers on Open Collective.
Some of the major new features include:
- We now can render into the terminal, similar to Ink.JS - a huge thanks to @Demonthos
- We have a new router in the spirit of React-Router @autarch
- We now have Fermi for global state management in the spirit of Recoil.JS
- Our desktop platform got major upgrades, getting closer to parity with Electron @mrxiaozhuox
- Our CLI tools now support HTML-to-RSX translation for converting 3rd party HTML into Dioxus @mrxiaozhuox
- Dioxus-Web is sped up by 2.5x with JS-based DOM manipulation (3x faster than React)
We also fixed and improved a bunch of stuff - check out the full list down below.
A New Renderer: Your terminal!
When Dioxus was initially released, we had very simple support for logging Dioxus elements out as TUI elements. In the past month or so, @Demonthos really stepped up and made the new crate a reality.
New Router
We totally revamped the router, switching away from the old yew-router approach to the more familiar React-Router. It's less type-safe but provides more flexibility and support for beautiful URLs.
Apps with routers are really simple now. It's easy to compose the "Router", a "Route", and "Links" to define how your app is laid out:
fn app(cx: Scope) -> Element {
cx.render(rsx! {
Router {
onchange: move |_| log::info!("Route changed!"),
ul {
Link { to: "/", li { "Go home!" } }
Link { to: "users", li { "List all users" } }
Link { to: "blog", li { "Blog posts" } }
}
Route { to: "/", "Home" }
Route { to: "/users", "User list" }
Route { to: "/users/:name", User {} }
Route { to: "/blog", "Blog list" }
Route { to: "/blog/:post", BlogPost {} }
Route { to: "", "Err 404 Route Not Found" }
}
})
}
We're also using hooks to parse the URL parameters and segments so you can interact with the router from anywhere deeply nested in your app.
#[derive(Deserialize)]
struct Query { name: String }
fn BlogPost(cx: Scope) -> Element {
let post = use_route(&cx).segment("post")?;
let query = use_route(&cx).query::<Query>()?;
cx.render(rsx!{
"Viewing post {post}"
"Name selected: {query}"
})
}
Give a big thanks to @autarch for putting in all the hard work to make this new router a reality.
The Router guide is available here - thanks to @dogedark.
Fermi for Global State Management
Managing state in your app can be challenging. Building global state management solutions can be even more challenging. For the first big attempt at building a global state management solution for Dioxus, we chose to keep it simple and follow in the footsteps of the Recoil.JS project.
Fermi uses the concept of "Atoms" for global state. These individual values can be get/set from anywhere in your app. Using state with Fermi is basically as simple as use_state
.
// Create a single value in an "Atom"
static TITLE: Atom<&str> = |_| "Hello";
// Read the value from anywhere in the app, subscribing to any changes
fn app(cx: Scope) -> Element {
let title = use_read(&cx, TITLE);
cx.render(rsx!{
h1 { "{title}" }
Child {}
})
}
// Set the value from anywhere in the app
fn Child(cx: Scope) -> Element {
let set_title = use_set(&cx, TITLE);
cx.render(rsx!{
button {
onclick: move |_| set_title("goodbye"),
"Say goodbye"
}
})
}
Inline Props Macro
For internal components, explicitly declaring props structs can become tedious. That's why we've built the new inline_props
macro. This macro lets you inline your props definition right into your component function arguments.
Simply add the inline_props
macro to your component:
#[inline_props]
fn Child<'a>(
cx: Scope,
name: String,
age: String,
onclick: EventHandler<'a, ClickEvent>
) -> Element {
cx.render(rsx!{
button {
"Hello, {name}"
"You are {age} years old"
onclick: move |evt| onclick.call(evt)
}
})
}
You won't be able to document each field or attach attributes so you should refrain from using it in libraries.
Props optional fields
Sometimes you don't want to specify every value in a component's props, since there might a lot. That's why the Props
macro now supports optional fields. You can use a combination of default
, strip_option
, and optional
to tune the exact behavior of properties fields.
#[derive(Props, PartialEq)]
struct ChildProps {
#[props(default = "client")]
name: String,
#[props(default)]
age: Option<u32>,
#[props(optional)]
age: Option<u32>,
}
// then to use the accompanying component
rsx!{
Child {
name: "asd",
}
}
Dioxus Web Speed Boost
We've changed how DOM patching works in Dioxus-Web; now, all of the DOM manipulation code is written in TypeScript and shared between our web, desktop, and mobile runtimes.
On an M1-max, the "create-rows" operation used to take 45ms. Now, it takes a mere 17ms - 3x faster than React. We expect an upcoming optimization to bring this number as low as 3ms.
Under the hood, we have a new string interning engine to cache commonly used tags and values on the Rust <-> JS boundary, resulting in significant performance improvements.
Overall, Dioxus apps are even more snappy than before.
Dioxus Desktop Window Context
A very welcome change, thanks AGAIN to @mrxiaozhuox is support for imperatively controlling the desktop window from your Dioxus code.
A bunch of new methods were added:
- Minimize and maximize window
- Close window
- Focus window
- Enable devtools on the fly
And more!
In addition, Dioxus Desktop now autoresolves asset locations, so you can easily add local images, JS, CSS, and then bundle it into an .app without hassle.
You can now build entirely borderless desktop apps:
CLI Tool
Thanks to the amazing work by @mrxiaozhuox, our CLI tool is fixed and working better than ever. The Dioxus-CLI sports a new development server, an HTML to RSX translation engine, a cargo fmt
-style command, a configuration scheme, and much more.
Unlike its counterpart, Trunk.rs
, the dioxus-cli supports running examples and tests, making it easier to test web-based projects and showcase web-focused libraries.
Async Improvements
Working with async isn't the easiest part of Rust. To help improve things, we've upgraded async support across the board in Dioxus.
First, we upgraded the use_future
hook. It now supports dependencies, which let you regenerate a future on the fly as its computed values change. It's never been easier to add datafetching to your Rust Web Apps:
fn RenderDog(cx: Scope, breed: String) -> Element {
let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
.await
.unwrap()
.json::<DogApi>()
.await
});
cx.render(match dog_request.value() {
Some(Ok(url)) => rsx!{ img { url: "{url}" } },
Some(Err(url)) => rsx!{ span { "Loading dog failed" } },
None => rsx!{ "Loading dog..." }
})
}
Additionally, we added better support for coroutines. You can now start, stop, resume, and message with asynchronous tasks. The coroutine is automatically exposed to the rest of your app via the Context API. For the vast majority of apps, Coroutines can satisfy all of your state management needs:
fn App(cx: Scope) -> Element {
let sync_task = use_coroutine(&cx, |rx| async ...