Merge branch 'master' into intigrate-collect-assets

This commit is contained in:
Evan Almloff committed 2023-12-08 08:49:17 -06:00
commit 66e2c02bf7
168 files changed
+3727 -858

No files matched your search

@@ -372,15 +372,65 @@ fn apply_request_parts_to_response<B>(
}
}
/// SSR renderer handler for Axum
pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
State((cfg, ssr_state)): State<(ServeConfig<P>, SSRState)>,
/// SSR renderer handler for Axum with added context injection.
///
/// # Example
/// ```rust,no_run
/// #![allow(non_snake_case)]
/// use std::sync::{Arc, Mutex};
///
/// use axum::routing::get;
/// use dioxus::prelude::*;
/// use dioxus_fullstack::{axum_adapter::render_handler_with_context, prelude::*};
///
/// fn app(cx: Scope) -> Element {
/// render! {
/// "hello!"
/// }
/// }
///
/// #[tokio::main]
/// async fn main() {
/// let cfg = ServeConfigBuilder::new(app, ())
/// .assets_path("dist")
/// .build();
/// let ssr_state = SSRState::new(&cfg);
///
/// // This could be any state you want to be accessible from your server
/// // functions using `[DioxusServerContext::get]`.
/// let state = Arc::new(Mutex::new("state".to_string()));
///
/// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
/// axum::Server::bind(&addr)
/// .serve(
/// axum::Router::new()
/// // Register server functions, etc.
/// // Note you probably want to use `register_server_fns_with_handler`
/// // to inject the context into server functions running outside
/// // of an SSR render context.
/// .fallback(get(render_handler_with_context).with_state((
/// move |ctx| ctx.insert(state.clone()).unwrap(),
/// cfg,
/// ssr_state,
/// )))
/// .into_make_service(),
/// )
/// .await
/// .unwrap();
/// }
/// ```
pub async fn render_handler_with_context<
P: Clone + serde::Serialize + Send + Sync + 'static,
F: FnMut(&mut DioxusServerContext),
>(
State((mut inject_context, cfg, ssr_state)): State<(F, ServeConfig<P>, SSRState)>,
request: Request<Body>,
) -> impl IntoResponse {
let (parts, _) = request.into_parts();
let url = parts.uri.path_and_query().unwrap().to_string();
let parts: Arc<RwLock<http::request::Parts>> = Arc::new(RwLock::new(parts.into()));
let server_context = DioxusServerContext::new(parts.clone());
let mut server_context = DioxusServerContext::new(parts.clone());
inject_context(&mut server_context);
match ssr_state.render(url, &cfg, &server_context).await {
Ok(rendered) => {
@@ -398,6 +448,14 @@ pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>
}
}
/// SSR renderer handler for Axum
pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
State((cfg, ssr_state)): State<(ServeConfig<P>, SSRState)>,
request: Request<Body>,
) -> impl IntoResponse {
render_handler_with_context(State((|_: &mut _| (), cfg, ssr_state)), request).await
}
fn report_err<E: std::fmt::Display>(e: E) -> Response<BoxBody> {
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
+19 -19
View File
@@ -89,26 +89,26 @@ impl Service for ServerFnHandler {
let parts = Arc::new(RwLock::new(parts));
// Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime
let (resp_tx, resp_rx) = tokio::sync::oneshot::channel();
let pool = get_local_pool();
pool.spawn_pinned({
let function = function.clone();
let mut server_context = server_context.clone();
server_context.parts = parts;
move || async move {
let data = match function.encoding() {
Encoding::Url | Encoding::Cbor => &body,
Encoding::GetJSON | Encoding::GetCBOR => &query,
};
let server_function_future = function.call((), data);
let server_function_future =
ProvideServerContext::new(server_function_future, server_context.clone());
let resp = server_function_future.await;
resp_tx.send(resp).unwrap();
}
});
let result = resp_rx.await.unwrap();
let result = pool
.spawn_pinned({
let function = function.clone();
let mut server_context = server_context.clone();
server_context.parts = parts;
move || async move {
let data = match function.encoding() {
Encoding::Url | Encoding::Cbor => &body,
Encoding::GetJSON | Encoding::GetCBOR => &query,
};
let server_function_future = function.call((), data);
let server_function_future = ProvideServerContext::new(
server_function_future,
server_context.clone(),
);
server_function_future.await
}
})
.await?;
let mut res = http::Response::builder();
// Set the headers from the server context
@@ -22,6 +22,7 @@ use std::sync::Arc;
/// will be allowed to continue
///
/// - dependencies: a tuple of references to values that are PartialEq + Clone
#[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
pub fn use_server_future<T, F, D>(
cx: &ScopeState,
dependencies: D,
+9 -2
View File
@@ -121,8 +121,15 @@ impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync
#[cfg(feature = "web")]
/// Launch the web application
pub fn launch_web(self) {
let cfg = self.web_cfg.hydrate(true);
dioxus_web::launch_with_props(self.component, get_root_props_from_document().unwrap(), cfg);
#[cfg(not(feature = "ssr"))]
{
let cfg = self.web_cfg.hydrate(true);
dioxus_web::launch_with_props(
self.component,
get_root_props_from_document().unwrap(),
cfg,
);
}
}
#[cfg(feature = "desktop")]
+5
View File
@@ -3,7 +3,9 @@ use tracing_futures::Instrument;
use http::{Request, Response};
/// A layer that wraps a service. This can be used to add additional information to the request, or response on top of some other service
pub trait Layer: Send + Sync + 'static {
/// Wrap a boxed service with this layer
fn layer(&self, inner: BoxedService) -> BoxedService;
}
@@ -17,7 +19,9 @@ where
}
}
/// A service is a function that takes a request and returns an async response
pub trait Service {
/// Run the service and produce a future that resolves to a response
fn run(
&mut self,
req: http::Request<hyper::body::Body>,
@@ -55,6 +59,7 @@ where
}
}
/// A boxed service is a type-erased service that can be used without knowing the underlying type
pub struct BoxedService(pub Box<dyn Service + Send>);
impl tower::Service<http::Request<hyper::body::Body>> for BoxedService {
+9
View File
@@ -41,6 +41,8 @@ pub mod prelude {
#[cfg(not(feature = "ssr"))]
pub use crate::html_storage::deserialize::get_root_props_from_document;
pub use crate::launch::LaunchBuilder;
#[cfg(feature = "ssr")]
pub use crate::layer::{Layer, Service};
#[cfg(all(feature = "ssr", feature = "router"))]
pub use crate::render::pre_cache_static_routes_with_props;
#[cfg(feature = "ssr")]
@@ -65,3 +67,10 @@ pub mod prelude {
pub use hooks::{server_cached::server_cached, server_future::use_server_future};
}
// Warn users about overlapping features
#[cfg(all(feature = "ssr", feature = "web"))]
compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `web` feature are overlapping. Please choose one or the other.");
#[cfg(all(feature = "ssr", feature = "desktop"))]
compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `desktop` feature are overlapping. Please choose one or the other.");
+2
View File
@@ -45,6 +45,8 @@ impl SsrRendererPool {
.expect("couldn't spawn runtime")
.block_on(async move {
let mut vdom = VirtualDom::new_with_props(component, props);
// Make sure the evaluator is initialized
dioxus_ssr::eval::init_eval(vdom.base_scope());
let mut to = WriteBuffer { buffer: Vec::new() };
// before polling the future, we need to set the context
let prev_context =
+1 -1
View File
@@ -53,7 +53,7 @@ fn default_external_navigation_handler() -> fn(Scope) -> Element {
dioxus_router::prelude::FailureExternalNavigation
}
/// The configeration for the router
/// The configuration for the router
#[derive(Props, serde::Serialize, serde::Deserialize)]
pub struct FullstackRouterConfig<R>
where
-8
View File
@@ -125,14 +125,6 @@ impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry {
}
}
fn register(
url: &'static str,
server_function: ServerFunction,
encoding: server_fn::Encoding,
) -> Result<(), Self::Error> {
Self::register_explicit("", url, server_function, encoding)
}
/// Returns the server function registered at the given URL, or `None` if no function is registered at that URL.
fn get(url: &str) -> Option<server_fn::ServerFnTraitObj<()>> {
REGISTERED_SERVER_FUNCTIONS