removed some HydrationCtx things and improved tracing for DynChild

This commit is contained in:
Jose Quesada 2022-12-15 12:05:17 -06:00
parent 3b99d2d4fd
commit 422233eecf
4 changed files with 70 additions and 81 deletions

View file

@ -151,8 +151,6 @@ where
move |prev_run: Option<(Option<web_sys::Node>, ScopeDisposer)>| { move |prev_run: Option<(Option<web_sys::Node>, ScopeDisposer)>| {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let _guard = span.enter(); let _guard = span.enter();
#[cfg(debug_assertions)]
let _guard = trace_span!("DynChild reactive").entered();
let (new_child, disposer) = let (new_child, disposer) =
cx.run_child_scope(|cx| child_fn().into_view(cx)); cx.run_child_scope(|cx| child_fn().into_view(cx));

View file

@ -56,18 +56,6 @@ impl HydrationCtx {
unsafe { ID = id } unsafe { ID = id }
} }
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
pub(crate) fn set_id(cx: Scope) {
/* let new_id = if let Some(id) = cx.get_hydration_key() {
id + 1
} else {
0
}; */
let new_id = 0;
println!("setting ID to {new_id}");
unsafe { ID = new_id };
}
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn stop_hydrating() { pub(crate) fn stop_hydrating() {
unsafe { unsafe {

View file

@ -6,7 +6,7 @@
//! The DOM implementation for `leptos`. //! The DOM implementation for `leptos`.
#[cfg_attr(debug_assertions, macro_use)] #[cfg_attr(debug_assertions, macro_use)]
extern crate tracing; pub extern crate tracing;
mod components; mod components;
mod events; mod events;
@ -19,7 +19,6 @@ mod node_ref;
mod ssr; mod ssr;
mod transparent; mod transparent;
use cfg_if::cfg_if; use cfg_if::cfg_if;
pub use components::*; pub use components::*;
pub use events::typed as ev; pub use events::typed as ev;
@ -29,7 +28,7 @@ pub use hydration::HydrationCtx;
pub use js_sys; pub use js_sys;
use leptos_reactive::Scope; use leptos_reactive::Scope;
pub use logging::*; pub use logging::*;
pub use macro_helpers::{IntoClass, IntoAttribute, IntoProperty}; pub use macro_helpers::{IntoAttribute, IntoClass, IntoProperty};
pub use node_ref::*; pub use node_ref::*;
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
use smallvec::SmallVec; use smallvec::SmallVec;
@ -109,7 +108,7 @@ where
{ {
#[cfg_attr( #[cfg_attr(
debug_assertions, debug_assertions,
instrument(level = "trace", name = "Fn() -> N", skip_all) instrument(level = "trace", name = "Fn() -> impl IntoView", skip_all)
)] )]
fn into_view(self, cx: Scope) -> View { fn into_view(self, cx: Scope) -> View {
DynChild::new(self).into_view(cx) DynChild::new(self).into_view(cx)
@ -206,7 +205,7 @@ impl Element {
attrs, attrs,
children, children,
id, id,
prerendered prerendered,
} = self; } = self;
let element = AnyElement { name, is_void, id }; let element = AnyElement { name, is_void, id };
@ -216,7 +215,7 @@ impl Element {
element, element,
attrs, attrs,
children: children.into_iter().collect(), children: children.into_iter().collect(),
prerendered prerendered,
} }
} }
} }
@ -255,14 +254,17 @@ impl Element {
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
#[track_caller] #[track_caller]
fn from_html<El: IntoElement>(el: El, html: impl Into<Cow<'static, str>>) -> Self { fn from_html<El: IntoElement>(
el: El,
html: impl Into<Cow<'static, str>>,
) -> Self {
Self { Self {
name: el.name(), name: el.name(),
is_void: el.is_void(), is_void: el.is_void(),
attrs: Default::default(), attrs: Default::default(),
children: Default::default(), children: Default::default(),
id: el.hydration_id(), id: el.hydration_id(),
prerendered: Some(html.into()) prerendered: Some(html.into()),
} }
} }
} }

View file

@ -2,12 +2,11 @@
use crate::{CoreComponent, HydrationCtx, IntoView, View}; use crate::{CoreComponent, HydrationCtx, IntoView, View};
use cfg_if::cfg_if; use cfg_if::cfg_if;
use futures::{Stream, StreamExt, stream::FuturesUnordered}; use futures::{stream::FuturesUnordered, Stream, StreamExt};
use itertools::Itertools; use itertools::Itertools;
use std::borrow::Cow;
use leptos_reactive::*; use leptos_reactive::*;
use std::borrow::Cow;
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
/// Renders the given function to a static HTML string. /// Renders the given function to a static HTML string.
/// ///
/// ``` /// ```
@ -23,12 +22,17 @@ pub fn render_to_string<F, N>(f: F) -> String
where where
F: FnOnce(Scope) -> N + 'static, F: FnOnce(Scope) -> N + 'static,
N: IntoView, N: IntoView,
{ {
let runtime = leptos_reactive::create_runtime(); let runtime = leptos_reactive::create_runtime();
HydrationCtx::reset_id(); HydrationCtx::reset_id();
let html = leptos_reactive::run_scope(runtime, |cx| f(cx).into_view(cx).render_to_string(cx));
runtime.dispose(); let html = leptos_reactive::run_scope(runtime, |cx| {
html.into_owned() f(cx).into_view(cx).render_to_string(cx)
});
runtime.dispose();
html.into_owned()
} }
/// Renders a function to a stream of HTML strings. /// Renders a function to a stream of HTML strings.
@ -43,7 +47,9 @@ where
/// it is waiting for a resource to resolve from the server, it doesn't run it initially. /// it is waiting for a resource to resolve from the server, it doesn't run it initially.
/// 3) HTML fragments to replace each `<Suspense/>` fallback with its actual data as the resources /// 3) HTML fragments to replace each `<Suspense/>` fallback with its actual data as the resources
/// read under that `<Suspense/>` resolve. /// read under that `<Suspense/>` resolve.
pub fn render_to_stream(view: impl FnOnce(Scope) -> View + 'static) -> impl Stream<Item = String> { pub fn render_to_stream(
view: impl FnOnce(Scope) -> View + 'static,
) -> impl Stream<Item = String> {
render_to_stream_with_prefix(view, |_| "".into()) render_to_stream_with_prefix(view, |_| "".into())
} }
@ -63,44 +69,47 @@ pub fn render_to_stream(view: impl FnOnce(Scope) -> View + 'static) -> impl Stre
/// read under that `<Suspense/>` resolve. /// read under that `<Suspense/>` resolve.
pub fn render_to_stream_with_prefix( pub fn render_to_stream_with_prefix(
view: impl FnOnce(Scope) -> View + 'static, view: impl FnOnce(Scope) -> View + 'static,
prefix: impl FnOnce(Scope) -> Cow<'static, str> + 'static prefix: impl FnOnce(Scope) -> Cow<'static, str> + 'static,
) -> impl Stream<Item = String> { ) -> impl Stream<Item = String> {
HydrationCtx::reset_id(); HydrationCtx::reset_id();
// create the runtime // create the runtime
let runtime = create_runtime(); let runtime = create_runtime();
let ((shell, prefix, pending_resources, pending_fragments, serializers), _, disposer) = let (
run_scope_undisposed(runtime, { (shell, prefix, pending_resources, pending_fragments, serializers),
move |cx| { _,
// the actual app body/template code disposer,
// this does NOT contain any of the data being loaded asynchronously in resources ) = run_scope_undisposed(runtime, {
let shell = view(cx).render_to_string(cx); move |cx| {
// the actual app body/template code
// this does NOT contain any of the data being loaded asynchronously in resources
let shell = view(cx).render_to_string(cx);
let resources = cx.all_resources(); let resources = cx.all_resources();
let pending_resources = serde_json::to_string(&resources).unwrap(); let pending_resources = serde_json::to_string(&resources).unwrap();
let prefix = prefix(cx); let prefix = prefix(cx);
( (
shell, shell,
prefix, prefix,
pending_resources, pending_resources,
cx.pending_fragments(), cx.pending_fragments(),
cx.serialization_resolvers(), cx.serialization_resolvers(),
) )
}
});
let fragments = FuturesUnordered::new();
for (fragment_id, fut) in pending_fragments {
fragments.push(async move { (fragment_id, fut.await) })
} }
});
let fragments = FuturesUnordered::new();
for (fragment_id, fut) in pending_fragments {
fragments.push(async move { (fragment_id, fut.await) })
}
// resources and fragments // resources and fragments
// stream HTML for each <Suspense/> as it resolves // stream HTML for each <Suspense/> as it resolves
let fragments = fragments.map(|(fragment_id, html)| { let fragments = fragments.map(|(fragment_id, html)| {
format!( format!(
r#" r#"
<template id="{fragment_id}f">{html}</template> <template id="{fragment_id}f">{html}</template>
<script> <script>
var frag = document.getElementById("{fragment_id}"); var frag = document.getElementById("{fragment_id}");
@ -108,27 +117,26 @@ pub fn render_to_stream_with_prefix(
if(frag) frag.replaceWith(tpl.content.cloneNode(true)); if(frag) frag.replaceWith(tpl.content.cloneNode(true));
</script> </script>
"# "#
) )
}); });
// stream data for each Resource as it resolves // stream data for each Resource as it resolves
let resources = let resources = serializers.map(|(id, json)| {
serializers.map(|(id, json)| { let id = serde_json::to_string(&id).unwrap();
let id = serde_json::to_string(&id).unwrap(); format!(
format!( r#"<script>
r#"<script>
if(__LEPTOS_RESOURCE_RESOLVERS.get({id})) {{ if(__LEPTOS_RESOURCE_RESOLVERS.get({id})) {{
__LEPTOS_RESOURCE_RESOLVERS.get({id})({json:?}) __LEPTOS_RESOURCE_RESOLVERS.get({id})({json:?})
}} else {{ }} else {{
__LEPTOS_RESOLVED_RESOURCES.set({id}, {json:?}); __LEPTOS_RESOLVED_RESOURCES.set({id}, {json:?});
}} }}
</script>"#, </script>"#,
) )
}); });
// HTML for the view function and script to store resources // HTML for the view function and script to store resources
futures::stream::once(async move { futures::stream::once(async move {
format!( format!(
r#" r#"
{prefix} {prefix}
{shell} {shell}
<script> <script>
@ -137,7 +145,7 @@ pub fn render_to_stream_with_prefix(
__LEPTOS_RESOURCE_RESOLVERS = new Map(); __LEPTOS_RESOURCE_RESOLVERS = new Map();
</script> </script>
"# "#
) )
}) })
// TODO these should be combined again in a way that chains them appropriately // TODO these should be combined again in a way that chains them appropriately
// such that individual resources can resolve before all fragments are done // such that individual resources can resolve before all fragments are done
@ -145,23 +153,16 @@ pub fn render_to_stream_with_prefix(
.chain(resources) .chain(resources)
// dispose of Scope and Runtime // dispose of Scope and Runtime
.chain(futures::stream::once(async move { .chain(futures::stream::once(async move {
disposer.dispose(); disposer.dispose();
runtime.dispose(); runtime.dispose();
Default::default() Default::default()
})) }))
} }
impl View { impl View {
/// Consumes the node and renders it into an HTML string. /// Consumes the node and renders it into an HTML string.
pub fn render_to_string(self, cx: Scope) -> Cow<'static, str> { pub fn render_to_string(self, cx: Scope) -> Cow<'static, str> {
//cx.set_hydration_key(HydrationCtx::current_id()); self.render_to_string_helper()
HydrationCtx::set_id(cx);
let s = self.render_to_string_helper();
//cx.set_hydration_key(HydrationCtx::current_id());
s
} }
pub(crate) fn render_to_string_helper(self) -> Cow<'static, str> { pub(crate) fn render_to_string_helper(self) -> Cow<'static, str> {
@ -299,7 +300,7 @@ impl View {
} }
}) })
.join(""); .join("");
if el.is_void { if el.is_void {
format!("<{tag_name}{attrs}/>").into() format!("<{tag_name}{attrs}/>").into()
} else { } else {
@ -308,7 +309,7 @@ impl View {
.into_iter() .into_iter()
.map(|node| node.render_to_string_helper()) .map(|node| node.render_to_string_helper())
.join(""); .join("");
format!("<{tag_name}{attrs}>{children}</{tag_name}>").into() format!("<{tag_name}{attrs}>{children}</{tag_name}>").into()
} }
} }