mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
fix other fullstack adapters
This commit is contained in:
parent
694bef0d93
commit
89b1e56fc3
9 changed files with 105 additions and 95 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -10966,16 +10966,11 @@ name = "warp-hello-world"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-fullstack",
|
|
||||||
"dioxus-web",
|
|
||||||
"execute",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"simple_logger",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"tracing-wasm",
|
"tracing-wasm",
|
||||||
"warp",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
//! Run with:
|
//! Run with:
|
||||||
//!
|
//!
|
||||||
//! ```sh
|
//! ```sh
|
||||||
//! dx build --features web --release
|
//! dx serve --platform fullstack
|
||||||
//! cargo run --features ssr --release
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![allow(non_snake_case, unused)]
|
#![allow(non_snake_case, unused)]
|
||||||
|
@ -10,14 +9,10 @@ use dioxus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
fn app() -> Element {
|
fn app() -> Element {
|
||||||
// let state = use_server_future(|| async move { get_server_data().await.unwrap() })?;
|
|
||||||
// let state = state.value();
|
|
||||||
|
|
||||||
let mut count = use_signal(|| 0);
|
let mut count = use_signal(|| 0);
|
||||||
let text = use_signal(|| "...".to_string());
|
let text = use_signal(|| "...".to_string());
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
// div { "Server state: {state}" }
|
|
||||||
h1 { "High-Five counter: {count}" }
|
h1 { "High-Five counter: {count}" }
|
||||||
button { onclick: move |_| count += 1, "Up high!" }
|
button { onclick: move |_| count += 1, "Up high!" }
|
||||||
button { onclick: move |_| count -= 1, "Down low!" }
|
button { onclick: move |_| count -= 1, "Down low!" }
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
//! Run with:
|
//! Run with:
|
||||||
//!
|
//!
|
||||||
//! ```sh
|
//! ```sh
|
||||||
//! dx build --features web --release
|
//! dx serve --platform fullstack
|
||||||
//! cargo run --features ssr --release
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
//! Run with:
|
//! Run with:
|
||||||
//!
|
//!
|
||||||
//! ```sh
|
//! ```sh
|
||||||
//! dx build --features web --release
|
//! dx serve --platform fullstack
|
||||||
//! cargo run --features ssr --release
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![allow(non_snake_case, unused)]
|
#![allow(non_snake_case, unused)]
|
||||||
|
|
|
@ -7,19 +7,14 @@ publish = false
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus-web = { workspace = true, features=["hydrate"], optional = true }
|
dioxus = { workspace = true, features = ["fullstack"] }
|
||||||
dioxus = { workspace = true }
|
|
||||||
dioxus-fullstack = { workspace = true }
|
|
||||||
serde = "1.0.159"
|
serde = "1.0.159"
|
||||||
warp = { version = "0.3.3", optional = true }
|
|
||||||
execute = "0.2.12"
|
|
||||||
reqwest = "0.11.18"
|
|
||||||
simple_logger = "4.2.0"
|
|
||||||
tracing-wasm = "0.2.1"
|
tracing-wasm = "0.2.1"
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber = "0.3.17"
|
tracing-subscriber = "0.3.17"
|
||||||
|
reqwest = "0.11.18"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
ssr = ["warp", "dioxus-fullstack/warp"]
|
ssr = ["dioxus/warp"]
|
||||||
web = ["dioxus-web"]
|
web = ["dioxus/web"]
|
||||||
|
|
|
@ -1,31 +1,17 @@
|
||||||
//! Run with:
|
//! Run with:
|
||||||
//!
|
//!
|
||||||
//! ```sh
|
//! ```sh
|
||||||
//! dx build --features web --release
|
//! dx serve --platform fullstack
|
||||||
//! cargo run --features ssr --release
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![allow(non_snake_case, unused)]
|
#![allow(non_snake_case, unused)]
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_fullstack::{launch, prelude::*};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)]
|
|
||||||
struct AppProps {
|
|
||||||
count: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(cx: Scope<AppProps>) -> Element {
|
|
||||||
let state =
|
|
||||||
use_server_future((), |()| async move { get_server_data().await.unwrap() })?.value();
|
|
||||||
|
|
||||||
|
fn app() -> Element {
|
||||||
let mut count = use_signal(|| 0);
|
let mut count = use_signal(|| 0);
|
||||||
let text = use_signal(|| "...".to_string());
|
let text = use_signal(|| "...".to_string());
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
|
||||||
"Server state: {state}"
|
|
||||||
}
|
|
||||||
h1 { "High-Five counter: {count}" }
|
h1 { "High-Five counter: {count}" }
|
||||||
button { onclick: move |_| count += 1, "Up high!" }
|
button { onclick: move |_| count += 1, "Up high!" }
|
||||||
button { onclick: move |_| count -= 1, "Down low!" }
|
button { onclick: move |_| count -= 1, "Down low!" }
|
||||||
|
@ -46,14 +32,14 @@ fn app(cx: Scope<AppProps>) -> Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(PostServerData)]
|
#[server]
|
||||||
async fn post_server_data(data: String) -> Result<(), ServerFnError> {
|
async fn post_server_data(data: String) -> Result<(), ServerFnError> {
|
||||||
println!("Server received: {}", data);
|
println!("Server received: {}", data);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(GetServerData)]
|
#[server]
|
||||||
async fn get_server_data() -> Result<String, ServerFnError> {
|
async fn get_server_data() -> Result<String, ServerFnError> {
|
||||||
Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?)
|
Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?)
|
||||||
}
|
}
|
||||||
|
@ -64,5 +50,5 @@ fn main() {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
|
launch(app);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use dioxus_lib::prelude::*;
|
||||||
use http_body_util::{BodyExt, Limited};
|
use http_body_util::{BodyExt, Limited};
|
||||||
use hyper::body::Body as HyperBody;
|
use hyper::body::Body as HyperBody;
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
|
@ -201,10 +202,11 @@ pub trait DioxusRouterExt {
|
||||||
///
|
///
|
||||||
/// fn app() -> Element {todo!()}
|
/// fn app() -> Element {todo!()}
|
||||||
/// ```
|
/// ```
|
||||||
fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
fn serve_dioxus_application(
|
||||||
self,
|
self,
|
||||||
server_fn_path: &'static str,
|
server_fn_path: &'static str,
|
||||||
cfg: impl Into<ServeConfig<P>>,
|
cfg: impl Into<ServeConfig>,
|
||||||
|
virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,10 +283,11 @@ impl DioxusRouterExt for Router {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
fn serve_dioxus_application(
|
||||||
self,
|
self,
|
||||||
server_fn_path: &'static str,
|
server_fn_path: &'static str,
|
||||||
cfg: impl Into<ServeConfig<P>>,
|
cfg: impl Into<ServeConfig>,
|
||||||
|
virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cfg = cfg.into();
|
let cfg = cfg.into();
|
||||||
|
|
||||||
|
@ -376,19 +379,26 @@ async fn convert_response(response: HyperResponse, res: &mut Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handler that renders a Dioxus application to HTML using server-side rendering.
|
/// A handler that renders a Dioxus application to HTML using server-side rendering.
|
||||||
pub struct SSRHandler<P: Clone> {
|
pub struct SSRHandler {
|
||||||
cfg: ServeConfig<P>,
|
config: ServeConfig,
|
||||||
|
virtual_dom: Box<dyn Fn() -> VirtualDom + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Clone> SSRHandler<P> {
|
impl SSRHandler {
|
||||||
/// Creates a new SSR handler with the given configuration.
|
/// Creates a new SSR handler with the given configuration.
|
||||||
pub fn new(cfg: ServeConfig<P>) -> Self {
|
pub fn new(
|
||||||
Self { cfg }
|
config: ServeConfig,
|
||||||
|
virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
virtual_dom: Box::new(virtual_dom),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler<P> {
|
impl Handler for SSRHandler {
|
||||||
async fn handle(
|
async fn handle(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
|
|
|
@ -52,6 +52,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::server_fn_service;
|
use crate::server_fn_service;
|
||||||
|
use dioxus_lib::prelude::VirtualDom;
|
||||||
use server_fn::{Encoding, Payload, ServerFunctionRegistry};
|
use server_fn::{Encoding, Payload, ServerFunctionRegistry};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -179,68 +180,85 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R
|
||||||
/// todo!()
|
/// todo!()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
pub fn serve_dioxus_application(
|
||||||
server_fn_route: &'static str,
|
server_fn_route: &'static str,
|
||||||
cfg: impl Into<ServeConfig<P>>,
|
cfg: impl Into<ServeConfig>,
|
||||||
|
virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> BoxedFilter<(impl Reply,)> {
|
) -> BoxedFilter<(impl Reply,)> {
|
||||||
let cfg = cfg.into();
|
let cfg = cfg.into();
|
||||||
// Serve the dist folder and the index.html file
|
// Serve the dist folder and the index.html file
|
||||||
let serve_dir = warp::fs::dir(cfg.assets_path);
|
let serve_dir = warp::fs::dir(cfg.assets_path);
|
||||||
|
|
||||||
|
let virtual_dom_factory =
|
||||||
|
Arc::new(virtual_dom_factory) as Arc<dyn Fn() -> VirtualDom + Send + Sync + 'static>;
|
||||||
|
|
||||||
connect_hot_reload()
|
connect_hot_reload()
|
||||||
// First register the server functions
|
// First register the server functions
|
||||||
.or(register_server_fns(server_fn_route))
|
.or(register_server_fns(server_fn_route))
|
||||||
// Then the index route
|
// Then the index route
|
||||||
.or(path::end().and(render_ssr(cfg.clone())))
|
.or(path::end().and(render_ssr(cfg.clone(), {
|
||||||
|
let virtual_dom_factory = virtual_dom_factory.clone();
|
||||||
|
move || virtual_dom_factory()
|
||||||
|
})))
|
||||||
// Then the static assets
|
// Then the static assets
|
||||||
.or(serve_dir)
|
.or(serve_dir)
|
||||||
// Then all other routes
|
// Then all other routes
|
||||||
.or(render_ssr(cfg))
|
.or(render_ssr(cfg, move || virtual_dom_factory()))
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Server render the application.
|
/// Server render the application.
|
||||||
pub fn render_ssr<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
pub fn render_ssr(
|
||||||
cfg: ServeConfig<P>,
|
cfg: ServeConfig,
|
||||||
|
virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> impl Filter<Extract = (impl Reply,), Error = warp::Rejection> + Clone {
|
) -> impl Filter<Extract = (impl Reply,), Error = warp::Rejection> + Clone {
|
||||||
warp::get()
|
warp::get()
|
||||||
.and(request_parts())
|
.and(request_parts())
|
||||||
.and(with_ssr_state(&cfg))
|
.and(with_ssr_state(&cfg, virtual_dom_factory))
|
||||||
.then(move |parts: http::request::Parts, renderer: SSRState| {
|
.then(
|
||||||
let route = parts.uri.path().to_string();
|
move |parts: http::request::Parts,
|
||||||
let parts = Arc::new(RwLock::new(parts));
|
(renderer, virtual_dom_factory): (
|
||||||
let cfg = cfg.clone();
|
SSRState,
|
||||||
async move {
|
Arc<dyn Fn() -> VirtualDom + Send + Sync + 'static>,
|
||||||
let server_context = DioxusServerContext::new(parts);
|
)| {
|
||||||
|
let route = parts.uri.path().to_string();
|
||||||
|
let parts = Arc::new(RwLock::new(parts));
|
||||||
|
let cfg = cfg.clone();
|
||||||
|
async move {
|
||||||
|
let server_context = DioxusServerContext::new(parts);
|
||||||
|
|
||||||
match renderer.render(route, &cfg, &server_context).await {
|
match renderer
|
||||||
Ok(rendered) => {
|
.render(route, &cfg, move || virtual_dom_factory(), &server_context)
|
||||||
let crate::render::RenderResponse { html, freshness } = rendered;
|
.await
|
||||||
|
{
|
||||||
|
Ok(rendered) => {
|
||||||
|
let crate::render::RenderResponse { html, freshness } = rendered;
|
||||||
|
|
||||||
let mut res = Response::builder()
|
let mut res = Response::builder()
|
||||||
.header("Content-Type", "text/html")
|
.header("Content-Type", "text/html")
|
||||||
.body(html)
|
.body(html)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let headers_mut = res.headers_mut();
|
let headers_mut = res.headers_mut();
|
||||||
let headers = server_context.response_parts().unwrap().headers.clone();
|
let headers = server_context.response_parts().unwrap().headers.clone();
|
||||||
for (key, value) in headers.iter() {
|
for (key, value) in headers.iter() {
|
||||||
headers_mut.insert(key, value.clone());
|
headers_mut.insert(key, value.clone());
|
||||||
|
}
|
||||||
|
freshness.write(headers_mut);
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!("Failed to render ssr: {}", err);
|
||||||
|
Response::builder()
|
||||||
|
.status(500)
|
||||||
|
.body("Failed to render ssr".into())
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
freshness.write(headers_mut);
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
tracing::error!("Failed to render ssr: {}", err);
|
|
||||||
Response::builder()
|
|
||||||
.status(500)
|
|
||||||
.body("Failed to render ssr".into())
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An extractor for the request parts (used in [DioxusServerContext]). This will extract the method, uri, query, and headers from the request.
|
/// An extractor for the request parts (used in [DioxusServerContext]). This will extract the method, uri, query, and headers from the request.
|
||||||
|
@ -273,11 +291,20 @@ pub fn request_parts(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_ssr_state<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
fn with_ssr_state(
|
||||||
cfg: &ServeConfig<P>,
|
cfg: &ServeConfig,
|
||||||
) -> impl Filter<Extract = (SSRState,), Error = std::convert::Infallible> + Clone {
|
virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
|
) -> impl Filter<
|
||||||
|
Extract = ((
|
||||||
|
SSRState,
|
||||||
|
Arc<dyn Fn() -> VirtualDom + Send + Sync + 'static>,
|
||||||
|
),),
|
||||||
|
Error = std::convert::Infallible,
|
||||||
|
> + Clone {
|
||||||
let renderer = SSRState::new(cfg);
|
let renderer = SSRState::new(cfg);
|
||||||
warp::any().map(move || renderer.clone())
|
let virtual_dom_factory =
|
||||||
|
Arc::new(virtual_dom_factory) as Arc<dyn Fn() -> VirtualDom + Send + Sync + 'static>;
|
||||||
|
warp::any().map(move || (renderer.clone(), virtual_dom_factory.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -170,15 +170,19 @@ impl Config {
|
||||||
let router = {
|
let router = {
|
||||||
// Serve the dist folder and the index.html file
|
// Serve the dist folder and the index.html file
|
||||||
let serve_dir = warp::fs::dir(cfg.assets_path);
|
let serve_dir = warp::fs::dir(cfg.assets_path);
|
||||||
|
let build_virtual_dom = Arc::new(build_virtual_dom);
|
||||||
|
|
||||||
router
|
router
|
||||||
.or(connect_hot_reload())
|
.or(connect_hot_reload())
|
||||||
// Then the index route
|
// Then the index route
|
||||||
.or(warp::path::end().and(render_ssr(cfg.clone())))
|
.or(warp::path::end().and(render_ssr(cfg.clone(), {
|
||||||
|
let build_virtual_dom = build_virtual_dom.clone();
|
||||||
|
move || build_virtual_dom()
|
||||||
|
})))
|
||||||
// Then the static assets
|
// Then the static assets
|
||||||
.or(serve_dir)
|
.or(serve_dir)
|
||||||
// Then all other routes
|
// Then all other routes
|
||||||
.or(render_ssr(cfg))
|
.or(render_ssr(cfg, move || build_virtual_dom()))
|
||||||
};
|
};
|
||||||
warp::serve(router.boxed().with(warp::filters::compression::gzip()))
|
warp::serve(router.boxed().with(warp::filters::compression::gzip()))
|
||||||
.run(addr)
|
.run(addr)
|
||||||
|
|
Loading…
Reference in a new issue