Fix fullstack axum integration docs (#3263)

* Fix broken fullstack doc tests

* include all features in doc test

* fix clippy
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-12-02 11:35:13 -08:00
1 parent 354c4ce9cc
commit 9dc567255a
8 files changed
+51 -116

No files matched your search

+1
View File
@@ -89,6 +89,7 @@ args = [
"test",
"--doc",
"--workspace",
"--all-features",
]
private = true
+1
View File
@@ -22,6 +22,7 @@ fn main() {
// Turn off rustfmt since we're doing layouts and routes in the same enum
#[derive(Routable, Clone, Debug, PartialEq)]
#[rustfmt::skip]
#[allow(clippy::empty_line_after_outer_attr)]
enum Route {
// Wrap Home in a Navbar Layout
#[layout(NavBar)]
+5 -72
View File
@@ -73,9 +73,11 @@ First, make sure your `axum` dependency is optional and enabled by the server fe
[dependencies]
dioxus = { version = "*", features = ["fullstack"] }
axum = { version = "0.7.0", optional = true }
tokio = { version = "1.0", features = ["full"], optional = true }
dioxus-cli-config = { version = "*", optional = true }
[features]
server = ["dioxus/server", "dep:axum"]
server = ["dioxus/server", "dep:axum", "dep:tokio", "dioxus-cli-config"]
web = ["dioxus/web"]
```
@@ -87,77 +89,8 @@ use dioxus::prelude::*;
// The entry point for the server
#[cfg(feature = "server")]
fn main() {
// Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address
// and we use the generated address the CLI gives us
let address = dioxus_cli_config::fullstack_address_or_localhost();
// Set up the axum router
let router = axum::Router::new()
// You can add a dioxus application to the router with the `serve_dioxus_application` method
// This will add a fallback route to the router that will serve your component and server functions
.serve_dioxus_application(ServeConfigBuilder::default(), App);
// Finally, we can launch the server
let router = router.into_make_service();
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
axum::serve(listener, router).await.unwrap();
}
// For any other platform, we just launch the app
#[cfg(not(feature = "server"))]
fn main() {
dioxus::launch(App);
}
#[component]
fn App() -> Element {
let mut meaning = use_signal(|| None);
rsx! {
h1 { "Meaning of life: {meaning:?}" }
button {
onclick: move |_| async move {
if let Ok(data) = get_meaning("life the universe and everything".into()).await {
meaning.set(data);
}
},
"Run a server function"
}
}
}
#[server]
async fn get_meaning(of: String) -> Result<Option<u32>, ServerFnError> {
Ok(of.contains("life").then(|| 42))
}
```
## Axum Integration
If you have an existing Axum router or you need more control over the server, you can use the [`DioxusRouterExt`](https://docs.rs/dioxus-fullstack/0.6.0-alpha.2/dioxus_fullstack/prelude/trait.DioxusRouterExt.html) trait to integrate with your existing Axum router.
First, make sure your `axum` dependency is optional and enabled by the server feature flag. Axum cannot be compiled to wasm, so if it is enabled by default, it will cause a compile error:
```toml
[dependencies]
dioxus = { version = "*", features = ["fullstack"] }
axum = { version = "0.7.0", optional = true }
[features]
server = ["dioxus/server", "dep:axum"]
web = ["dioxus/web"]
```
Then we can set up dioxus with the axum server:
```rust, no_run
#![allow(non_snake_case)]
use dioxus::prelude::*;
// The entry point for the server
#[cfg(feature = "server")]
fn main() {
#[tokio::main]
async fn main() {
// Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address
// and we use the generated address the CLI gives us
let address = dioxus_cli_config::fullstack_address_or_localhost();
+11 -3
View File
@@ -3,13 +3,16 @@ This method interacts with information from the current request. The request may
1. The initial SSR render if this method called from a [`Component`](dioxus_lib::prelude::component) or a [`server`](crate::prelude::server) function that is called during the initial render
```rust
# use dioxus::prelude::*;
#[component]
fn PrintHtmlRequestInfo() -> Element {
// The server context only exists on the server, so we need to put it behind a server_only! config
server_only! {
// Since we are calling this from a component, the server context that is returned will be from
// the html request for ssr rendering
println!("headers are {:?}", server_context().request_parts().headers);
let context = server_context();
let request_parts = context.request_parts();
println!("headers are {:?}", request_parts.headers);
}
rsx! {}
}
@@ -18,11 +21,14 @@ fn PrintHtmlRequestInfo() -> Element {
2. A request to a [`server`](crate::prelude::server) function called directly from the client (either on desktop/mobile or on the web frontend after the initial render)
```rust
# use dioxus::prelude::*;
#[server]
async fn read_headers() -> Result<(), ServerFnError> {
// Since we are calling this from a server function, the server context that is may be from the
// initial request or a request from the client
println!("headers are {:?}", server_context().request_parts().headers);
let context = server_context();
let request_parts = context.request_parts();
println!("headers are {:?}", request_parts.headers);
Ok(())
}
@@ -32,7 +38,9 @@ fn CallServerFunction() -> Element {
button {
// If you click the button, the server function will be called and the server context will be
// from the client request
onclick: move |_| read_headers().await,
onclick: move |_| async {
_ = read_headers().await
},
"Call server function"
}
}
+14 -26
View File
@@ -40,16 +40,10 @@ impl ServeConfigBuilder {
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg = cfg.with_server_cfg(ServeConfigBuilder::default().incremental(IncrementalRendererConfig::default()));
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// // Only set the server config if the server feature is enabled
/// .with_cfg(server_only!(ServeConfigBuilder::default().incremental(IncrementalRendererConfig::default())))
/// .launch(app);
/// ```
pub fn incremental(mut self, cfg: dioxus_isrg::IncrementalRendererConfig) -> Self {
@@ -92,26 +86,20 @@ impl ServeConfigBuilder {
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg = cfg.with_server_cfg(ServeConfigBuilder::default().root_id("app"));
/// }
///
/// // You also need to set the root id in your web config
/// web! {
/// cfg = cfg.with_web_config(dioxus::web::Config::default().rootname("app"));
/// }
///
/// // And desktop config
/// desktop! {
/// cfg = cfg.with_desktop_config(dioxus::desktop::Config::default().with_root_name("app"));
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// // Only set the server config if the server feature is enabled
/// .with_cfg(server_only! {
/// ServeConfigBuilder::default().root_id("app")
/// })
/// // You also need to set the root id in your web config
/// .with_cfg(web! {
/// dioxus::web::Config::default().rootname("app")
/// })
/// // And desktop config
/// .with_cfg(desktop! {
/// dioxus::desktop::Config::default().with_root_name("app")
/// })
/// .launch(app);
/// ```
pub fn root_id(mut self, root_id: &'static str) -> Self {
+9 -6
View File
@@ -14,7 +14,10 @@
//! tokio::runtime::Runtime::new()
//! .unwrap()
//! .block_on(async move {
//! let listener = tokio::net::TcpListener::bind("127.0.0.01:8080")
//! // Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address
//! // and we use the generated address the CLI gives us
//! let address = dioxus_cli_config::fullstack_address_or_localhost();
//! let listener = tokio::net::TcpListener::bind(address)
//! .await
//! .unwrap();
//! axum::serve(
@@ -82,7 +85,7 @@ pub trait DioxusRouterExt<S> {
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// let addr = dioxus_cli_config::fullstack_address_or_localhost();
/// let router = axum::Router::new()
/// // Register server functions routes with the default handler
/// .register_server_functions()
@@ -107,7 +110,7 @@ pub trait DioxusRouterExt<S> {
/// # use std::sync::Arc;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// let addr = dioxus_cli_config::fullstack_address_or_localhost();
/// let router = axum::Router::new()
/// // Register server functions routes with the default handler
/// .register_server_functions_with_context(Arc::new(vec![Box::new(|| Box::new(1234567890u32))]))
@@ -127,7 +130,7 @@ pub trait DioxusRouterExt<S> {
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// let addr = dioxus_cli_config::fullstack_address_or_localhost();
/// let router = axum::Router::new()
/// // Server side render the application, serve static assets, and register server functions
/// .serve_static_assets()
@@ -152,7 +155,7 @@ pub trait DioxusRouterExt<S> {
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// let addr = dioxus_cli_config::fullstack_address_or_localhost();
/// let router = axum::Router::new()
/// // Server side render the application, serve static assets, and register server functions
/// .serve_dioxus_application(ServeConfig::new().unwrap(), app)
@@ -358,7 +361,7 @@ impl RenderHandleState {
///
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// let addr = dioxus_cli_config::fullstack_address_or_localhost();
/// let router = axum::Router::new()
/// // Register server functions, etc.
/// // Note you can use `register_server_functions_with_context`
+10 -8
View File
@@ -161,10 +161,11 @@ mod server_fn_impl {
/// #[server]
/// async fn set_headers() -> Result<(), ServerFnError> {
/// let server_context = server_context();
/// let cookies = server_context.response_parts()
/// .headers()
/// let response_parts = server_context.response_parts();
/// let cookies = response_parts
/// .headers
/// .get("Cookie")
/// .ok_or_else(|| ServerFnError::msg("failed to find Cookie header in the response"))?;
/// .ok_or_else(|| ServerFnError::new("failed to find Cookie header in the response"))?;
/// println!("{:?}", cookies);
/// Ok(())
/// }
@@ -185,8 +186,8 @@ mod server_fn_impl {
/// async fn set_headers() -> Result<(), ServerFnError> {
/// let server_context = server_context();
/// server_context.response_parts_mut()
/// .headers_mut()
/// .insert("Cookie", "dioxus=fullstack");
/// .headers
/// .insert("Cookie", http::HeaderValue::from_static("dioxus=fullstack"));
/// Ok(())
/// }
/// ```
@@ -205,10 +206,11 @@ mod server_fn_impl {
/// #[server]
/// async fn read_headers() -> Result<(), ServerFnError> {
/// let server_context = server_context();
/// let id: &i32 = server_context.request_parts()
/// let request_parts = server_context.request_parts();
/// let id: &i32 = request_parts
/// .extensions
/// .get()
/// .ok_or_else(|| ServerFnError::msg("failed to find i32 extension in the request"))?;
/// .ok_or_else(|| ServerFnError::new("failed to find i32 extension in the request"))?;
/// println!("{:?}", id);
/// Ok(())
/// }
@@ -231,7 +233,7 @@ mod server_fn_impl {
/// let id: i32 = server_context.request_parts_mut()
/// .extensions
/// .remove()
/// .ok_or_else(|| ServerFnError::msg("failed to find i32 extension in the request"))?;
/// .ok_or_else(|| ServerFnError::new("failed to find i32 extension in the request"))?;
/// println!("{:?}", id);
/// Ok(())
/// }
@@ -181,7 +181,6 @@ impl ImageAssetOptions {
/// # use manganis::{asset, Asset, ImageAssetOptions, ImageSize};
/// const _: Asset = asset!("/assets/image.png", ImageAssetOptions::new().with_size(ImageSize::Manual { width: 512, height: 512 }));
/// ```
pub const fn with_size(self, size: ImageSize) -> Self {
Self { size, ..self }
}