feat(fullstack): support wasm target

This commit is contained in:
Koji AGAWA committed 2024-02-17 05:12:33 +09:00
1 parent a454f2c7ac
commit 1f0e03ca19
9 files changed
+190 -128

No files matched your search

+93 -87
View File
@@ -7,13 +7,33 @@ use dioxus_ssr::{
Renderer,
};
use serde::Serialize;
use std::future::Future;
use std::sync::Arc;
use std::sync::RwLock;
use tokio::task::spawn_blocking;
use tokio::task::{spawn_blocking, JoinHandle};
use crate::prelude::*;
use dioxus_lib::prelude::*;
fn spawn_platform<Fut>(f: impl FnOnce() -> Fut + Send + 'static) -> JoinHandle<Fut::Output>
where
Fut: Future + 'static,
Fut::Output: Send + 'static,
{
#[cfg(not(target_arch = "wasm32"))]
{
spawn_blocking(move || {
tokio::runtime::Runtime::new()
.expect("couldn't spawn runtime")
.block_on(f())
})
}
#[cfg(target_arch = "wasm32")]
{
tokio::task::spawn_local(f())
}
}
enum SsrRendererPool {
Renderer(RwLock<Vec<Renderer>>),
Incremental(RwLock<Vec<dioxus_ssr::incremental::IncrementalRenderer>>),
@@ -39,51 +59,41 @@ impl SsrRendererPool {
let (tx, rx) = tokio::sync::oneshot::channel();
spawn_blocking(move || {
tokio::runtime::Runtime::new()
.expect("couldn't spawn runtime")
.block_on(async move {
let mut vdom = virtual_dom_factory();
let mut to = WriteBuffer { buffer: Vec::new() };
// before polling the future, we need to set the context
let prev_context =
SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
// poll the future, which may call server_context()
tracing::info!("Rebuilding vdom");
let _ = vdom.rebuild(&mut NoOpMutations);
vdom.wait_for_suspense().await;
tracing::info!("Suspense resolved");
// after polling the future, we need to restore the context
SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
spawn_platform(move || async move {
let mut vdom = virtual_dom_factory();
let mut to = WriteBuffer { buffer: Vec::new() };
// before polling the future, we need to set the context
let prev_context = SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
// poll the future, which may call server_context()
tracing::info!("Rebuilding vdom");
let _ = vdom.rebuild(&mut NoOpMutations);
vdom.wait_for_suspense().await;
tracing::info!("Suspense resolved");
// after polling the future, we need to restore the context
SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
if let Err(err) = wrapper.render_before_body(&mut *to) {
let _ = tx.send(Err(err));
return;
}
if let Err(err) = renderer.render_to(&mut to, &vdom) {
let _ = tx.send(Err(
dioxus_ssr::incremental::IncrementalRendererError::RenderError(
err,
),
));
return;
}
if let Err(err) = wrapper.render_after_body(&mut *to) {
let _ = tx.send(Err(err));
return;
}
match String::from_utf8(to.buffer) {
Ok(html) => {
let _ =
tx.send(Ok((renderer, RenderFreshness::now(None), html)));
}
Err(err) => {
dioxus_ssr::incremental::IncrementalRendererError::Other(
Box::new(err),
);
}
}
});
if let Err(err) = wrapper.render_before_body(&mut *to) {
let _ = tx.send(Err(err));
return;
}
if let Err(err) = renderer.render_to(&mut to, &vdom) {
let _ = tx.send(Err(
dioxus_ssr::incremental::IncrementalRendererError::RenderError(err),
));
return;
}
if let Err(err) = wrapper.render_after_body(&mut *to) {
let _ = tx.send(Err(err));
return;
}
match String::from_utf8(to.buffer) {
Ok(html) => {
let _ = tx.send(Ok((renderer, RenderFreshness::now(None), html)));
}
Err(err) => {
dioxus_ssr::incremental::IncrementalRendererError::Other(Box::new(err));
}
}
});
let (renderer, freshness, html) = rx.await.unwrap()?;
pool.write().unwrap().push(renderer);
@@ -98,53 +108,49 @@ impl SsrRendererPool {
let (tx, rx) = tokio::sync::oneshot::channel();
let server_context = server_context.clone();
spawn_blocking(move || {
tokio::runtime::Runtime::new()
.expect("couldn't spawn runtime")
.block_on(async move {
let mut to = WriteBuffer { buffer: Vec::new() };
match renderer
.render(
route,
virtual_dom_factory,
&mut *to,
|vdom| {
Box::pin(async move {
// before polling the future, we need to set the context
let prev_context = SERVER_CONTEXT
.with(|ctx| ctx.replace(Box::new(server_context)));
// poll the future, which may call server_context()
tracing::info!("Rebuilding vdom");
let _ = vdom.rebuild(&mut NoOpMutations);
vdom.wait_for_suspense().await;
tracing::info!("Suspense resolved");
// after polling the future, we need to restore the context
SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
})
},
&wrapper,
)
.await
{
Ok(freshness) => {
match String::from_utf8(to.buffer).map_err(|err| {
dioxus_ssr::incremental::IncrementalRendererError::Other(
Box::new(err),
)
}) {
Ok(html) => {
let _ = tx.send(Ok((freshness, html)));
}
Err(err) => {
let _ = tx.send(Err(err));
}
}
spawn_platform(move || async move {
let mut to = WriteBuffer { buffer: Vec::new() };
match renderer
.render(
route,
virtual_dom_factory,
&mut *to,
|vdom| {
Box::pin(async move {
// before polling the future, we need to set the context
let prev_context = SERVER_CONTEXT
.with(|ctx| ctx.replace(Box::new(server_context)));
// poll the future, which may call server_context()
tracing::info!("Rebuilding vdom");
let _ = vdom.rebuild(&mut NoOpMutations);
vdom.wait_for_suspense().await;
tracing::info!("Suspense resolved");
// after polling the future, we need to restore the context
SERVER_CONTEXT.with(|ctx| ctx.replace(prev_context));
})
},
&wrapper,
)
.await
{
Ok(freshness) => {
match String::from_utf8(to.buffer).map_err(|err| {
dioxus_ssr::incremental::IncrementalRendererError::Other(Box::new(
err,
))
}) {
Ok(html) => {
let _ = tx.send(Ok((freshness, html)));
}
Err(err) => {
let _ = tx.send(Err(err));
}
}
})
}
Err(err) => {
let _ = tx.send(Err(err));
}
}
});
let (freshness, html) = rx.await.unwrap()?;