codify "platform" into resolution logic, server-fn/fullstack overhaul (#4596)

overhaul dioxus fullstack using a new implementation of server_fn

This PR is a complete rewrite of dioxus fullstack designed to improve compatibility with axum and to fix a number of compilation errors based on feature flag unification plumbing through macros.
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-10-03 18:26:19 -07:00
1 parent 8421c3aef0
commit f2b1c6d97f
424 files changed
+17284 -6624

No files matched your search

+54 -37
View File
@@ -5,14 +5,13 @@
// - Hydration
#![allow(non_snake_case)]
use dioxus::fullstack::{codec::JsonEncoding, commit_initial_chunk, BoxedStream, Websocket};
use dioxus::prelude::*;
use futures::{channel::mpsc, SinkExt, StreamExt};
use dioxus::fullstack::{commit_initial_chunk, Websocket};
use dioxus::{fullstack::WebSocketOptions, prelude::*};
fn main() {
dioxus::LaunchBuilder::new()
.with_cfg(server_only! {
dioxus::fullstack::ServeConfig::builder().enable_out_of_order_streaming()
dioxus::server::ServeConfig::builder().enable_out_of_order_streaming()
})
.with_context(1234u32)
.launch(app);
@@ -23,7 +22,7 @@ fn app() -> Element {
let mut text = use_signal(|| "...".to_string());
rsx! {
document::Title { "hello axum! {count}" }
Title { "hello axum! {count}" }
h1 { "hello axum! {count}" }
button { class: "increment-button", onclick: move |_| count += 1, "Increment" }
button {
@@ -75,12 +74,14 @@ fn DefaultServerFnCodec() -> Element {
#[cfg(feature = "server")]
async fn assert_server_context_provided() {
use dioxus::server::{extract, FromContext};
let FromContext(i): FromContext<u32> = extract().await.unwrap();
assert_eq!(i, 1234u32);
// todo!("replace server context....")
// use dioxus::server::{extract, FromContext};
// let FromContext(i): FromContext<u32> = extract().await.unwrap();
// assert_eq!(i, 1234u32);
}
#[server(PostServerData)]
// #[server(PostServerData)]
#[server]
async fn post_server_data(data: String) -> ServerFnResult {
assert_server_context_provided().await;
println!("Server received: {}", data);
@@ -88,7 +89,8 @@ async fn post_server_data(data: String) -> ServerFnResult {
Ok(())
}
#[server(GetServerData)]
// #[server(GetServerData)]
#[server]
async fn get_server_data() -> ServerFnResult<String> {
assert_server_context_provided().await;
Ok("Hello from the server!".to_string())
@@ -105,9 +107,10 @@ async fn get_server_data_empty_vec(empty_vec: Vec<String>) -> ServerFnResult<Vec
#[server]
async fn server_error() -> ServerFnResult<String> {
use dioxus_core::AnyhowContext;
assert_server_context_provided().await;
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
Err(ServerFnError::new("the server threw an error!"))
Err(None.context("Server error occurred")?)
}
#[component]
@@ -165,49 +168,50 @@ fn DocumentElements() -> Element {
fn Assets() -> Element {
#[used]
static _ASSET: Asset = asset!("/assets/image.png");
#[used]
static _OTHER_ASSET: Asset = asset!("/assets/nested");
static _STATIC_NO_HASH: Asset = asset!(
"/assets/image.png",
AssetOptions::image().with_hash_suffix(false)
);
#[used]
static _UNHASHED_FOLDER: Asset = asset!(
"/assets/nested/",
AssetOptions::folder().with_hash_suffix(false)
);
#[used]
static _EMBEDDED_FOLDER: Asset = asset!("/assets/nested");
rsx! {
img {
src: asset!("/assets/image.png"),
}
img {
src: "/assets/image.png",
src: "{_EMBEDDED_FOLDER}/image.png",
}
img {
src: "/assets/nested/image.png",
src: "{_UNHASHED_FOLDER}/image.png",
}
img {
src: "/assets/image.png",
}
}
}
#[server(protocol = Websocket<JsonEncoding, JsonEncoding>)]
async fn echo_ws(
input: BoxedStream<String, ServerFnError>,
) -> ServerFnResult<BoxedStream<String, ServerFnError>> {
let mut input = input;
let (mut tx, rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(msg) = input.next().await {
let _ = tx.send(msg.map(|msg| msg.to_ascii_uppercase())).await;
}
});
Ok(rx.into())
}
/// This component tests websocket server functions
#[component]
fn WebSockets() -> Element {
let mut received = use_signal(String::new);
use_future(move || async move {
let (mut tx, rx) = mpsc::channel(1);
let mut receiver = echo_ws(rx.into()).await.unwrap();
tx.send(Ok("hello world".to_string())).await.unwrap();
while let Some(Ok(msg)) = receiver.next().await {
println!("Received: {}", msg);
received.set(msg);
let socket = echo_ws(WebSocketOptions::default()).await.unwrap();
socket.send("hello world".to_string()).await.unwrap();
while let Ok(msg) = socket.recv().await {
received.write().push_str(&msg);
}
});
@@ -218,3 +222,16 @@ fn WebSockets() -> Element {
}
}
}
#[get("/api/echo_ws")]
async fn echo_ws(options: WebSocketOptions) -> Result<Websocket> {
info!("Upgrading to websocket");
Ok(options.on_upgrade(
|mut tx: dioxus::fullstack::TypedWebsocket<String, String>| async move {
while let Ok(msg) = tx.recv().await {
let _ = tx.send(msg.to_ascii_uppercase()).await;
}
},
))
}