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.
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) - Support for the new
islands-router
features that allow a client-side routing experience while using islands (see theislands_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 useServerFnError
(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)
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. (Apologies if I missed any big features! I will add missing things to release notes as release nears.)
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:
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 #3274
- impl Dispose for Callback types and add try_run to the Callable trait by @basro in #3371
- feat(breaking): allow make
PossibleRouteMatch
dyn-safe by @gbj in #3421 - chore: upgrade
axum
tov0.8
by @sabify in #3439 - feat: Add more options for generating server fn routes by @spencewenski in #3438
- change: allow
IntoFuture
forSuspend::new()
(closes #3509) by @gbj in #3532 - fix: remove
Default
impl forLeptosOptions
andConfFile
by @chrisp60 in #3522 - Fixing closing brace by @thestarmaker in #3539
- AddAnyAttr for AnyView for non-erased by @zakstucke in #3553
- "Update axum paths to 0.8 syntax" by @zakstucke in #3555
- Keep
AddAnyAttr
logic contained by @gbj in #3562 - fix: Actix stream error handling with 0.8 error types by @gbj in #3574
- RenderHtml::into_owned by @zakstucke in #3580
- Binary size wins by @zakstucke in #3566
- fix: remove extra placeholder in Vec of text nodes (closes #3583) by @gbj in #3592
- fix: occasional use-after-disposed panic in Suspense by @gbj in #3595
- projects/bevy3d_ui Migrate to leptos 0.7.7 by @martinfrances107 in #3596
- projects/bevy3d_ui: Bevy migration by @martinfrances107 in #3597
- Minor: leptos_config - Bump the "config" crate to version 0.15.8 by @martinfrances107 in #3594
- Minor: Bump itertools to "0.14.0" by @martinfrances107 in #3593
- Minor: Bumped version of convert_case to 0.7 by @martinfrances107 in #3590
- Minor: "wasm-bindgen" - Moved the crate definition up to the root workspace by @martinfrances107 in #3588
- Remove getrandom by @martinfrances107 in #3589
- Minor: Bump tokio to 1.43. by @martinfrances107 in #3600
- projects/bevy3d_ui: Bevy - Bugfix, clippy and crate bump by @martinfrances107 in #3603
- Add transpose to the OptionStoreExt by @mahdi739 in #3534
- feat: allow pausing and resuming effects by @gbj in #3599
- Impl into for subfields by @jvdwrf in #3579
- fix: reorder pause check in new_isomorphic by @gbj in #3613
- Minor: drop create_signal form the landing page. by @martinfrances107 in #3611
- chore: update
either_of
minimum version in workspace by @gbj in #3612 - Internally erase html elements by @zakstucke in #3614
- fix: hydration of
()
by @gbj in #3615 - Put serde_json in the root workspace by @martinfrances107 in #3610
- feat: support
Option<_>
instyle:
(closes #3568) by @gbj in #3618 - fix: only render meta tags when rendered, not when created (closes #3629) by @gbj in #3630
- Erased routing, codegen opts by @zakstucke in #3623
- fix: allow decoding already-decoded URI components (closes #3606) by @gbj in #3628
- change: remove unused
Result
alias by @gbj in #3543 - chore(ci): update pinned nightly version by @gbj in #3644
- chore: fix Axum test setup by @gbj in #3651
- feat: support
IntoSplitSignal
for(Signal<T>, SignalSetter<T>)
(closes #3634) by @gbj in #3643 - feat: map and and_then for resource variants by @TERRORW0LF in #3652
- fix: avoid hydration issues with
HashedStylesheet
(closes #3633) by @gbj in #3654 - Islands router by @gbj in #3502
- Implement
Debug
forArcField
andField
by @mahdi739 in #3660 - Minor: examples/server_fns_axum - Bumped various packages (not axum). by @martinfrances107 in #3655
- Erased mode in CI by @zakstucke in #3640
- fix: tweak bounds on For for backwards-compat by @gbj in #3663
- fix: do not double-insert hash character in URLs (closes #3647) by @gbj in #3661
- fix: param segments should not match an empty string that contains only
/
separator (closes #3527) by @gbj in #3662 - fix: ensure cleanups run for all replaced nested routes (closes #3665) by @gbj in #3666
- Minor: clippy - Replace mem::replace with Option::replace by @martinfrances107 in #3668
- Implement several into traits for store fields (0.8) by @mahdi739 in #3658
- fix: point
bind:group
to correct location (closes #3678) by @gbj in #3680 - fix: enum stack size by @sabify in #3677
- fix: semver and feature handy script for update nightly by @sabify in #3674
- Implement
IntoClass
for store fields by @mahdi739 in #3670 - fix: untrack in
NodeRef::on_load()
to avoid re-triggering it if you read something reactively (closes #3684) by @gbj in #3686 ImmediateEffect
by @QuartzLibrary in #3650ImmediateEffect
follow up by @QuartzLibrary in #3692- fix: Ensure reactive functions passed to
TextProp
are kept reactive (closes: #3689) by @mahdi739 in #3690 - Add websocket support for server functions by @ealmloff in #3656
- fix: broken type inference for
Action::new_unsync
(closes #3328) by @gbj in #3705
New Contributors
- @ryo33 made their first contribution in #3274
- @basro made their first contribution in #3371
- @TERRORW0LF made their first contribution in #3652
- @QuartzLibrary made their first contribution in #3650
Full Changelog: v0.7.7...0.8.0-alpha