Make it easier to provide context to fullstack (#2515)

* pass context providers into server functions

* add an example for FromContext

* clean up DioxusRouterExt

* fix server function context

* fix fullstack desktop example

* fix axum auth example

* fix fullstack context type

* fix context providers path
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-06-18 20:38:06 -05:00
1 parent 7ee3dc41fc
commit b0caf442ab
12 files changed
+152 -64

No files matched your search

+67 -25
View File
@@ -22,7 +22,7 @@
//! listener,
//! axum::Router::new()
//! // Server side render the application, serve static assets, and register server functions
//! .serve_dioxus_application("", ServerConfig::new(app, ()))
//! .serve_dioxus_application(ServerConfig::new(), app)
//! .into_make_service(),
//! )
//! .await
@@ -60,12 +60,13 @@ use axum::{
http::{Request, Response, StatusCode},
response::IntoResponse,
};
use dioxus_lib::prelude::VirtualDom;
use dioxus_lib::prelude::{Element, VirtualDom};
use futures_util::Future;
use http::header::*;
use std::sync::Arc;
use crate::launch::ContextProviders;
use crate::prelude::*;
/// A extension trait with utilities for integrating Dioxus with your Axum router.
@@ -74,9 +75,8 @@ pub trait DioxusRouterExt<S> {
///
/// # Example
/// ```rust
/// use dioxus_lib::prelude::*;
/// use dioxus_fullstack::prelude::*;
///
/// # use dioxus_lib::prelude::*;
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
@@ -84,23 +84,49 @@ pub trait DioxusRouterExt<S> {
/// .serve(
/// axum::Router::new()
/// // Register server functions routes with the default handler
/// .register_server_fns("")
/// .register_server_functions()
/// .into_make_service(),
/// )
/// .await
/// .unwrap();
/// }
/// ```
fn register_server_fns(self) -> Self;
fn register_server_functions(self) -> Self
where
Self: Sized,
{
self.register_server_functions_with_context(Default::default())
}
/// Registers server functions with some additional context to insert into the [`DioxusServerContext`] for that handler.
///
/// # Example
/// ```rust
/// # use dioxus_lib::prelude::*;
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// axum::Server::bind(&addr)
/// .serve(
/// axum::Router::new()
/// // Register server functions routes with the default handler
/// .register_server_functions_with_context(vec![Box::new(|| 1234567890u32)])
/// .into_make_service(),
/// )
/// .await
/// .unwrap();
/// }
/// ```
fn register_server_functions_with_context(self, context_providers: ContextProviders) -> Self;
/// Serves the static WASM for your Dioxus application (except the generated index.html).
///
/// # Example
/// ```rust
/// #![allow(non_snake_case)]
/// use dioxus_lib::prelude::*;
/// use dioxus_fullstack::prelude::*;
///
/// # #![allow(non_snake_case)]
/// # use dioxus_lib::prelude::*;
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
@@ -133,10 +159,9 @@ pub trait DioxusRouterExt<S> {
///
/// # Example
/// ```rust
/// #![allow(non_snake_case)]
/// use dioxus_lib::prelude::*;
/// use dioxus_fullstack::prelude::*;
///
/// # #![allow(non_snake_case)]
/// # use dioxus_lib::prelude::*;
/// # use dioxus_fullstack::prelude::*;
/// #[tokio::main]
/// async fn main() {
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
@@ -144,7 +169,7 @@ pub trait DioxusRouterExt<S> {
/// .serve(
/// axum::Router::new()
/// // Server side render the application, serve static assets, and register server functions
/// .serve_dioxus_application("", ServerConfig::new(app, ()))
/// .serve_dioxus_application(ServeConfig::new(), )
/// .into_make_service(),
/// )
/// .await
@@ -158,7 +183,7 @@ pub trait DioxusRouterExt<S> {
fn serve_dioxus_application(
self,
cfg: impl Into<ServeConfig>,
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
app: fn() -> Element,
) -> impl Future<Output = Self> + Send + Sync
where
Self: Sized;
@@ -168,12 +193,29 @@ impl<S> DioxusRouterExt<S> for Router<S>
where
S: Send + Sync + Clone + 'static,
{
fn register_server_fns(mut self) -> Self {
fn register_server_functions_with_context(
mut self,
context_providers: ContextProviders,
) -> Self {
use http::method::Method;
let context_providers = Arc::new(context_providers);
for (path, method) in server_fn::axum::server_fn_paths() {
tracing::trace!("Registering server function: {} {}", method, path);
let handler = move |req| handle_server_fns_inner(path, || {}, req);
let context_providers = context_providers.clone();
let handler = move |req| {
handle_server_fns_inner(
path,
move |server_context| {
for context_provider in context_providers.iter() {
let context = context_provider();
_ = server_context.insert_any(context);
}
},
req,
)
};
self = match method {
Method::GET => self.route(path, get(handler)),
Method::POST => self.route(path, post(handler)),
@@ -234,7 +276,7 @@ where
fn serve_dioxus_application(
self,
cfg: impl Into<ServeConfig>,
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
app: fn() -> Element,
) -> impl Future<Output = Self> + Send + Sync {
let cfg = cfg.into();
async move {
@@ -244,7 +286,7 @@ where
let mut server = self
.serve_static_assets(cfg.assets_path.clone())
.await
.register_server_fns();
.register_server_functions();
#[cfg(all(feature = "hot-reload", debug_assertions))]
{
@@ -254,7 +296,7 @@ where
server.fallback(get(render_handler).with_state((
cfg,
Arc::new(build_virtual_dom),
Arc::new(move || VirtualDom::new(app)),
ssr_state,
)))
}
@@ -311,7 +353,7 @@ type AxumHandler<F> = (
/// .serve(
/// axum::Router::new()
/// // Register server functions, etc.
/// // Note you probably want to use `register_server_fns_with_handler`
/// // Note you can use `register_server_functions_with_context`
/// // to inject the context into server functions running outside
/// // of an SSR render context.
/// .fallback(get(render_handler_with_context).with_state((
@@ -383,7 +425,7 @@ fn report_err<E: std::fmt::Display>(e: E) -> Response<axum::body::Body> {
/// A handler for Dioxus server functions. This will run the server function and return the result.
async fn handle_server_fns_inner(
path: &str,
additional_context: impl Fn() + 'static + Clone + Send,
additional_context: impl Fn(&DioxusServerContext) + 'static + Clone + Send,
req: Request<Body>,
) -> impl IntoResponse {
use server_fn::middleware::Service;
@@ -398,7 +440,7 @@ async fn handle_server_fns_inner(
server_fn::axum::get_server_fn_service(&path_string)
{
let server_context = DioxusServerContext::new(Arc::new(tokio::sync::RwLock::new(parts)));
additional_context();
additional_context(&server_context);
// store Accepts and Referrer in case we need them for redirect (below)
let accepts_html = req