v0.8.0
leptos-rs/leptosv0.8.0May 1, 2025by benwis
AI Summary
A major version bump introducing Axum 0.8 support, islands-router features, WebSocket support for server functions, and significant DX improvements including `erase_components` optimization.
Key Highlights
- Axum 0.8 support (required major version bump)
- Islands-router features for client-side routing with islands
- WebSocket support for server functions
- `erase_components` optimization for faster compile times
- `LocalResource` API cleanup (removed `SendWrapper`)
Breaking Changes
- `LocalResource` no longer exposes `SendWrapper` in its API
- Type constraints for `FromServerFnError` changed to allow any implementing type
New Features
- WebSocket protocol support for server functions
- `erase_components` default for `cargo-leptos`
- `IntoSplitSignal` for `(Signal<T>, SignalSetter<T>)`
- `impl From<MappedSignal<T>> for Signal<T>`
Full Release Notes
*Changelog relative to `0.7.8`. *
0.8 has been planned for a while, primarily to accommodate small changes that arose during the course of testing and adopting 0.7, most of which are technically semver-breaking but should not meaningfully affect user code. I think it's a significant QOL and user DX upgrade and I'm excited to properly release it.
Noteworthy features:
- Axum 0.8 support. (This alone required a major version bump, as we reexport some Axum types.) (thanks to @sabify for the migration work here)
- Significant improvements to compile times when using `--cfg=erase_components`, which is useful as a dev-mode optimization (thanks to @zakstucke) This is the default setting for `cargo-leptos` with its latest release, and can be set up manually for use with Trunk. (See docs [here](https://book.leptos.dev/getting_started/leptos_dx.html#4-use---cfgerase_components-during-development).)
- Support for the new `islands-router` features that allow a client-side routing experience while using islands (see the [`islands_router`](https://github.com/leptos-rs/leptos/tree/main/examples/islands_router) example) (this one was me)
- Improved server function error handling by allowing you to use any type that implements `FromServerFnError` rather than being constrained to use `ServerFnError` (see #3274). (Note: This will require changes if you're using a custom error type, but should be a better experience.) (thanks to @ryo33)
- Support for creating WebSockets via server fns (thanks to @ealmloff)
- Changes to make custom errors significantly more ergonomic when using server functions
- `LocalResource` no longer exposes a `SendWrapper` in the API for the types it returns. (**Breaking change**: this will require removing some `.as_deref()` and so on when using `LocalResource`, but ends up with a much better API.)
- Significantly improved DX/bugfixes for thread-local Actions.
As you can see this was a real team effort and, as always, I'm grateful for the contributions of everyone named above, and all those who made commits below.
### WebSocket Example
The WebSocket support is particularly exciting, as it allows you to call server functions using the default Rust `Stream` trait from the `futures` crate, and have those streams send messages over websockets without you needing to know anything about that process. The API landed in a place that feels like a great extension of the "server function" abstraction in which you can make HTTP requests as if they were ordinary async calls. The websocket stuff doesn't integrate directly with Resources/SSR (which make more sense for one-shot things) but is really easy to use:
```rust
use server_fn::{codec::JsonEncoding, BoxedStream, ServerFnError, Websocket};
// The websocket protocol can be used on any server function that accepts and returns a [`BoxedStream`]
// with items that can be encoded by the input and output encoding generics.
//
// In this case, the input and output encodings are [`Json`] and [`Json`], respectively which requires
// the items to implement [`Serialize`] and [`Deserialize`].
#[server(protocol = Websocket<JsonEncoding, JsonEncoding>)]
async fn echo_websocket(
input: BoxedStream<String, ServerFnError>,
) -> Result<BoxedStream<String, ServerFnError>, ServerFnError> {
use futures::channel::mpsc;
use futures::{SinkExt, StreamExt};
let mut input = input; // FIXME :-) server fn fields should pass mut through to destructure
// create a channel of outgoing websocket messages
// we'll return rx, so sending a message to tx will send a message to the client via the websocket
let (mut tx, rx) = mpsc::channel(1);
// spawn a task to listen to the input stream of messages coming in over the websocket
tokio::spawn(async move {
while let Some(msg) = input.next().await {
// do some work on each message, and then send our responses
tx.send(msg.map(|msg| msg.to_ascii_uppercase())).await;
}
});
Ok(rx.into())
}
#[component]
pub fn App() -> impl IntoView {
use futures::channel::mpsc;
use futures::StreamExt;
let (mut tx, rx) = mpsc::channel(1);
let latest = RwSignal::new(None);
// we'll only listen for websocket messages on the client
if cfg!(feature = "hydrate") {
spawn_local(async move {
match echo_websocket(rx.into()).await {
Ok(mut messages) => {
while let Some(msg) = messages.next().await {
latest.set(Some(msg));
}
}
Err(e) => leptos::logging::warn!("{e}"),
}
});
}
view! {
<input type="text" on:input:target=move |ev| {
tx.try_send(Ok(ev.target().value()));
}/>
<p>{latest}</p>
}
}
```
## What's Changed
* Allow any type that implements FromServerFnError as a replacement of the ServerFnError in server_fn by @ryo33 in https://github.com/leptos-rs/leptos/pull/3274
* impl Dispose for Callback types and add try_run to the Callable trait by @basro in https://github.com/leptos-rs/leptos/pull/3371
* feat(breaking): allow make `PossibleRouteMatch` dyn-safe by @gbj in https://github.com/leptos-rs/leptos/pull/3421
* chore: upgrade `axum` to `v0.8` by @sabify in https://github.com/leptos-rs/leptos/pull/3439
* feat: Add more options for generating server fn routes by @spencewenski in https://github.com/leptos-rs/leptos/pull/3438
* change: allow `IntoFuture` for `Suspend::new()` (closes #3509) by @gbj in https://github.com/leptos-rs/leptos/pull/3532
* fix: remove `Default` impl for `LeptosOptions` and `ConfFile` by @chrisp60 in https://github.com/leptos-rs/leptos/pull/3522
* Fixing closing brace by @thestarmaker in https://github.com/leptos-rs/leptos/pull/3539
* AddAnyAttr for AnyView for non-erased by @zakstucke in https://github.com/leptos-rs/leptos/pull/3553
* "Update axum paths to 0.8 syntax" by @zakstucke in https://github.com/leptos-rs/leptos/pull/3555
* Keep `AddAnyAttr` logic contained by @gbj in https://github.com/leptos-rs/leptos/pull/3562
* fix: Actix stream error handling with 0.8 error types by @gbj in https://github.com/leptos-rs/leptos/pull/3574
* RenderHtml::into_owned by @zakstucke in https://github.com/leptos-rs/leptos/pull/3580
* Binary size wins by @zakstucke in https://github.com/leptos-rs/leptos/pull/3566
* Internally erase html elements by @zakstucke in https://github.com/leptos-rs/leptos/pull/3614
* feat: support `Option<_>` in `style:` (closes #3568) by @gbj in https://github.com/leptos-rs/leptos/pull/3618
* Erased routing, codegen opts by @zakstucke in https://github.com/leptos-rs/leptos/pull/3623
* change: remove unused `Result` alias by @gbj in https://github.com/leptos-rs/leptos/pull/3543
* feat: support `IntoSplitSignal` for `(Signal<T>, SignalSetter<T>)` (closes #3634) by @gbj in https://github.com/leptos-rs/leptos/pull/3643
* fix: avoid hydration issues with `HashedStylesheet` (closes #3633) by @gbj in https://github.com/leptos-rs/leptos/pull/3654
* Islands router by @gbj in https://github.com/leptos-rs/leptos/pull/3502
* Erased mode in CI by @zakstucke in https://github.com/leptos-rs/leptos/pull/3640
* fix: tweak bounds on For for backwards-compat by @gbj in https://github.com/leptos-rs/leptos/pull/3663
* Implement several into traits for store fields (0.8) by @mahdi739 in https://github.com/leptos-rs/leptos/pull/3658
* Implement `IntoClass` for store fields by @mahdi739 in https://github.com/leptos-rs/leptos/pull/3670
* fix: Ensure reactive functions passed to `TextProp` are kept reactive (closes: #3689) by @mahdi739 in https://github.com/leptos-rs/leptos/pull/3690
* Add websocket support for server functions by @ealmloff in https://github.com/leptos-rs/leptos/pull/3656
* fix: broken type inference for `Action::new_unsync` (closes #3328) by @gbj in https://github.com/leptos-rs/leptos/pull/3705
* feat(reactive_stores): Replace `AsRef` bound of `StoreFieldIterator` blanket impl with `Len` bound by @DanikVitek in https://github.com/leptos-rs/leptos/pull/3701
* refactor: make `shell` parameter in `file_and_error_handler*` generic by @tversteeg in https://github.com/leptos-rs/leptos/pull/3711
* view!{} macro optimisation: don't wrap string types in closures when passing to ToChildren by @zakstucke in https://github.com/leptos-rs/leptos/pull/3716
* Remove SendWrapper from the external interface of LocalResource by @zakstucke in https://github.com/leptos-rs/leptos/pull/3715
* More flexible server fn macro api by @ealmloff in https://github.com/leptos-rs/leptos/pull/3725
* fix(CI): switch to stable in semver for most compatibility by @sabify in https://github.com/leptos-rs/leptos/pull/3737
* fix(CI): cancel in-group inflight and pending jobs on new pushes in pull requests by @sabify in https://github.com/leptos-rs/leptos/pull/3739
* fix(CI): free-up disk, properly gate nightly feature and pre-install deps by @sabify in https://github.com/leptos-rs/leptos/pull/3735
* ArcLocalResource fix (0.8) by @zakstucke in https://github.com/leptos-rs/leptos/pull/3741
* ArcLocalResource fix (0.7) by @zakstucke in https://github.com/leptos-rs/leptos/pull/3740
* fix(CI): cleanup the directory no matter of the results by @sabify in https://github.com/leptos-rs/leptos/pull/3743
* fix(CI): sermver job name by @sabify in https://github.com/leptos-rs/leptos/pull/3748
* chore: no need to filter out "nightly" feature as of #3735 by @sabify in https://github.com/leptos-rs/leptos/pull/3747
* fix: use signals rather than `Action::new_local()` (closes #3746) by @gbj in https://github.com/leptos-rs/leptos/pull/3749
* feat: switch `extract()` helper to use `ServerFnErrorErr` (closes #3745) by @ilyvion in https://github.com/leptos-rs/leptos/pull/3750
* docs(`Effect::watch`): refer to `dependency_fn` and `handler` args by @jmevel in https://github.com/leptos-rs/leptos/pull/3731
* Leptos 0.8 by @gbj in https://github.com/leptos-rs/leptos/pull/3529
* chore: ensure WASM target is installed for examples with provided `rust-toolchain.toml` (closes #3717) by @gbj in https://github.com/leptos-rs/leptos/pull/3752
* Make trailing comma optional for either macro by @NCura in https://github.com/leptos-rs/leptos/pull/3736
* chore: add `SignalSetter` to prelude (closes #3547) by @gbj in https://github.com/leptos-rs/leptos/pull/3753
* fix: properly feature gating ui macro tests (Closes #3742) by @sabify in https://github.com/leptos-rs/leptos/pull/3756
* fix(CI): optimize CI workflow by @sabify in https://github.com/leptos-rs/leptos/pull/3758
* fix(CI): remove duplicate semver ci, #3758 follow-up by @sabify in https://github.com/leptos-rs/leptos/pull/3764
* fix(CI): install deps only if needed, speeds up CI by @sabify in https://github.com/leptos-rs/leptos/pull/3768
* fix: support `IntoFragment` for single element (closes #3757) by @gbj in https://github.com/leptos-rs/leptos/pull/3759
* fix: clippy errors by @sabify in https://github.com/leptos-rs/leptos/pull/3772
* fix(CI): install deno only if needed, #3768 follow-up by @sabify in https://github.com/leptos-rs/leptos/pull/3773
* fix(CI): remove caching by @sabify in https://github.com/leptos-rs/leptos/pull/3776
* fix(CI): conditional executions of only changed examples by @sabify in https://github.com/leptos-rs/leptos/pull/3777
* Make docs match reality by @ilyvion in https://github.com/leptos-rs/leptos/pull/3775
* fix(CI): toolchain will be determined and test against by CI by @sabify in https://github.com/leptos-rs/leptos/pull/3778
* Reduce use local signals for `Action::new_local` and similar primitives by @gbj in https://github.com/leptos-rs/leptos/pull/3762
* Tweaks to `MaybeSendWrapperOption<_>` by @gbj in https://github.com/leptos-rs/leptos/pull/3781
* fix: correctly handle optional parameters in `ParentRoute` by @gbj in https://github.com/leptos-rs/leptos/pull/3784
* fix: router example build process by @sabify in https://github.com/leptos-rs/leptos/pull/3779
* fix(CI): run only the exact examples on the only examples change by @sabify in https://github.com/leptos-rs/leptos/pull/3782
* Re-export the codee crate by @zakstucke in https://github.com/leptos-rs/leptos/pull/3761
* fix: allow repeated `class=` for all tuples, not only static ones (closes #3794) by @gbj in https://github.com/leptos-rs/leptos/pull/3801
* Fix Store notification order for nested keyed fields by @gbj in https://github.com/leptos-rs/leptos/pull/3799
* Improved handling of `<Title/>` by @gbj in https://github.com/leptos-rs/leptos/pull/3793
* derive_local for ArcSignal<T, LocalStorage> by @zakstucke in https://github.com/leptos-rs/leptos/pull/3798
* fix: portal example by @sabify in https://github.com/leptos-rs/leptos/pull/3785
* feat: add support for more HTTP methods in server fn codecs by @ChosunOne in https://github.com/leptos-rs/leptos/pull/3797
* Store test fixes by @gbj in https://github.com/leptos-rs/leptos/pull/3803
* Add track_caller to store field methods by @jvdwrf in https://github.com/leptos-rs/leptos/pull/3805
* fix: allow custom status codes or redirects for route fallbacks by @gbj in https://github.com/leptos-rs/leptos/pull/3808
* fix: Move several Into* trait impls for store fields out of stable module for wider use by @mahdi739 in https://github.com/leptos-rs/leptos/pull/3807
* fix: remove `SendOption` from public API of actions by @gbj in https://github.com/leptos-rs/leptos/pull/3812
* feat: support aliased `Result` return types for `server_fn` by @ifiokjr in https://github.com/leptos-rs/leptos/pull/3755
* Migrate from Tailwind 3 to Tailwind 4 for the axum example. by @pico-bolero in https://github.com/leptos-rs/leptos/pull/3804
* pass key reference to `Selector::selected` by @flisky in https://github.com/leptos-rs/leptos/pull/3694
* fix: correctly establish root ownership for static site generation (closes #3822) by @gbj in https://github.com/leptos-rs/leptos/pull/3824
* fix: do not match static segment with last character missing before slash (closes #3817) by @gbj in https://github.com/leptos-rs/leptos/pull/3823
* fix: prevent race condition in executor initialization + docs, optimization and tests by @sabify in https://github.com/leptos-rs/leptos/pull/3802
* chore: missing Copy/Clone impls for MappedSignal by @gbj in https://github.com/leptos-rs/leptos/pull/3827
* Revert "Remove getrandom (#3589)" by @ilyvion in https://github.com/leptos-rs/leptos/pull/3830
* Introducing `cargo all-features clippy|nextest` part of build process by @sabify in https://github.com/leptos-rs/leptos/pull/3767
* feat: allow using different error types for req/resp with WebSockets, closes #3724 by @myypo in https://github.com/leptos-rs/leptos/pull/3766
* feat: enhancing server_fn errors by @sabify in https://github.com/leptos-rs/leptos/pull/3811
* fix: call `additional_context` after providing other server context in all cases by @gbj in https://github.com/leptos-rs/leptos/pull/3841
* fix: correctly decode base64-encoded server action error messages stored in URL by @gbj in https://github.com/leptos-rs/leptos/pull/3842
* fix: don't try to move keyed elements within the DOM if they're not yet mounted (closes #3844) by @gbj in https://github.com/leptos-rs/leptos/pull/3846
* chore(nightly): update proc-macro span file name method name by @gbj in https://github.com/leptos-rs/leptos/pull/3852
* fix: reactive_graph keymap impl and clippy warnings by @sabify in https://github.com/leptos-rs/leptos/pull/3843
* chore: ran cargo outdated. by @martinfrances107 in https://github.com/leptos-rs/leptos/pull/3722
* fix: close Actix websocket stream when browser disconnects (closes #3865) by @gbj in https://github.com/leptos-rs/leptos/pull/3866
* Error boundary fixes by @gbj in https://github.com/leptos-rs/leptos/pull/3870
* Forward lint attributes used with #[component] macro by @sathish-pv in https://github.com/leptos-rs/leptos/pull/3864
* Complete the migration of examples to Tailwind 4 by @nnmm in https://github.com/leptos-rs/leptos/pull/3861
* fix: Use stabilized ClipboardEvent by @feathecutie in https://github.com/leptos-rs/leptos/pull/3849
* Added header generation method to BrowserResponse by @rakshith-ravi in https://github.com/leptos-rs/leptos/pull/3873
* Prevent ScopedFuture stopping owner cleanup by @zakstucke in https://github.com/leptos-rs/leptos/pull/3863
* feat: enhancing `ByteStream` error handling by @sabify in https://github.com/leptos-rs/leptos/pull/3869
* fix: send/receive websocket data by @sabify in https://github.com/leptos-rs/leptos/pull/3848
* feat(examples): add WebSocket example by @sabify in https://github.com/leptos-rs/leptos/pull/3853
* chore: put `TextProp` in the prelude (closes #3877) by @huuff in https://github.com/leptos-rs/leptos/pull/3879
* fix(examples): websocket example tests fail on latency by @sabify in https://github.com/leptos-rs/leptos/pull/3880
* fix: correctly calculate starting index for first new key (closes #3828) by @gbj in https://github.com/leptos-rs/leptos/pull/3878
* fix: remove event listeners from Suspense fallback during SSR (closes #3871) by @gbj in https://github.com/leptos-rs/leptos/pull/3882
* fix(examples): broken favicons in hackernews examples (closes #3890) by @gbj in https://github.com/leptos-rs/leptos/pull/3891
* docs: add note about file hashing in `Stylesheet` docs by @gbj in https://github.com/leptos-rs/leptos/pull/3898
* fix(examples): incorrect routes in hackernews example (closes #3892) by @nickburlett in https://github.com/leptos-rs/leptos/pull/3894
* Fix some island-routing issues by @gbj in https://github.com/leptos-rs/leptos/pull/3901
* fix: prevent sibling context leakage in islands (closes #3902) by @gbj in https://github.com/leptos-rs/leptos/pull/3903
* fix: correct hydration for elements after island `children` (closes #3904) by @gbj in https://github.com/leptos-rs/leptos/pull/3905
* Fix leptos_debuginfo by @zakstucke in https://github.com/leptos-rs/leptos/pull/3899
* fix(examples): websocket tests fail (occasionally) second attemp by @sabify in https://github.com/leptos-rs/leptos/pull/3910
* feat: `impl From<MappedSignal<T>> for Signal<T>` (closes #3889) by @gbj in https://github.com/leptos-rs/leptos/pull/3897
## New Contributors
* @ryo33 made their first contribution in https://github.com/leptos-rs/leptos/pull/3274
* @basro made their first contribution in https://github.com/leptos-rs/leptos/pull/3371
* @ilyvion made their first contribution in https://github.com/leptos-rs/leptos/pull/3750
* @jmevel made their first contribution in https://github.com/leptos-rs/leptos/pull/3731
* @ChosunOne made their first contribution in https://github.com/leptos-rs/leptos/pull/3797
* @ifiokjr made their first contribution in https://github.com/leptos-rs/leptos/pull/3755
* @pico-bolero made their first contribution in https://github.com/leptos-rs/leptos/pull/3804
* @myypo made their first contribution in https://github.com/leptos-rs/leptos/pull/3766
* @sathish-pv made their first contribution in https://github.com/leptos-rs/leptos/pull/3864
* @nnmm made their first contribution in https://github.com/leptos-rs/leptos/pull/3861
* @feathecutie made their first contribution in https://github.com/leptos-rs/leptos/pull/3849
* @huuff made their first contribution in https://github.com/leptos-rs/leptos/pull/3879
* @nickburlett made their first contribution in https://github.com/leptos-rs/leptos/pull/3894
**Full Changelog**: https://github.com/leptos-rs/leptos/compare/v0.7.8...v0.8.0