Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ args = [
"test",
"--doc",
"--workspace",
"--all-features",
]
private = true

Expand Down
1 change: 1 addition & 0 deletions examples/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
77 changes: 5 additions & 72 deletions packages/fullstack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
```

Expand All @@ -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();
Expand Down
14 changes: 11 additions & 3 deletions packages/fullstack/docs/request_origin.md
Original file line number Diff line number Diff line change
Expand Up @@ -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! {}
}
Expand All @@ -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(())
}

Expand All @@ -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"
}
}
Expand Down
40 changes: 14 additions & 26 deletions packages/fullstack/src/serve_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
15 changes: 9 additions & 6 deletions packages/fullstack/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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()
Expand All @@ -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))]))
Expand All @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -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`
Expand Down
18 changes: 10 additions & 8 deletions packages/fullstack/src/server_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
/// }
Expand All @@ -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(())
/// }
/// ```
Expand All @@ -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(())
/// }
Expand All @@ -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(())
/// }
Expand Down
1 change: 0 additions & 1 deletion packages/manganis/manganis-core/src/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down