Fix fullstack axum integration docs (#3263)
* Fix broken fullstack doc tests * include all features in doc test * fix clippy
This commit is contained in:
1 parent
354c4ce9cc
commit
9dc567255a
8 files changed
+51
-116
No files matched your search
@@ -89,6 +89,7 @@ args = [
|
||||
"test",
|
||||
"--doc",
|
||||
"--workspace",
|
||||
"--all-features",
|
||||
]
|
||||
private = true
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user