Ver código fonte

Fix fullstack axum integration docs (#3263)

* Fix broken fullstack doc tests

* include all features in doc test

* fix clippy
Evan Almloff 6 meses atrás
pai
commit
9dc567255a

+ 1 - 0
Makefile.toml

@@ -89,6 +89,7 @@ args = [
   "test",
   "--doc",
   "--workspace",
+  "--all-features",
 ]
 private = true
 

+ 1 - 0
examples/router.rs

@@ -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
packages/fullstack/README.md

@@ -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
packages/fullstack/docs/request_origin.md

@@ -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
packages/fullstack/src/serve_config.rs

@@ -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
packages/fullstack/src/server/mod.rs

@@ -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
packages/fullstack/src/server_context.rs

@@ -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(())
         /// }

+ 0 - 1
packages/manganis/manganis-core/src/images.rs

@@ -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 }
     }