fix: properly handle islands used in the body of other islands (closes #2725)
This commit is contained in:
parent
6c749f5e24
commit
24775fb59b
|
@ -25,11 +25,7 @@ pub fn AutoReload(
|
|||
};
|
||||
|
||||
let script = include_str!("reload_script.js");
|
||||
view! {
|
||||
<script nonce=nonce>
|
||||
{format!("{script}({reload_port:?}, {protocol})")}
|
||||
</script>
|
||||
}
|
||||
view! { <script nonce=nonce>{format!("{script}({reload_port:?}, {protocol})")}</script> }
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -49,6 +45,9 @@ pub fn HydrationScripts(
|
|||
#[cfg(not(feature = "nonce"))]
|
||||
let nonce = None::<String>;
|
||||
let script = if islands {
|
||||
if let Some(sc) = Owner::current_shared_context() {
|
||||
sc.set_is_hydrating(false);
|
||||
}
|
||||
include_str!("./island_script.js")
|
||||
} else {
|
||||
include_str!("./hydration_script.js")
|
||||
|
@ -56,7 +55,13 @@ pub fn HydrationScripts(
|
|||
|
||||
view! {
|
||||
<link rel="modulepreload" href=format!("/{pkg_path}/{output_name}.js") nonce=nonce.clone()/>
|
||||
<link rel="preload" href=format!("/{pkg_path}/{wasm_output_name}.wasm") r#as="fetch" r#type="application/wasm" crossorigin=nonce.clone().unwrap_or_default()/>
|
||||
<link
|
||||
rel="preload"
|
||||
href=format!("/{pkg_path}/{wasm_output_name}.wasm")
|
||||
r#as="fetch"
|
||||
r#type="application/wasm"
|
||||
crossorigin=nonce.clone().unwrap_or_default()
|
||||
/>
|
||||
<script type="module" nonce=nonce>
|
||||
{format!("{script}({pkg_path:?}, {output_name:?}, {wasm_output_name:?})")}
|
||||
</script>
|
||||
|
|
|
@ -181,7 +181,7 @@ where
|
|||
/// Hydrates any islands that are currently present on the page.
|
||||
#[cfg(feature = "hydrate")]
|
||||
pub fn hydrate_islands() {
|
||||
use hydration_context::HydrateSharedContext;
|
||||
use hydration_context::{HydrateSharedContext, SharedContext};
|
||||
use std::sync::Arc;
|
||||
|
||||
// use wasm-bindgen-futures to drive the reactive system
|
||||
|
@ -193,7 +193,9 @@ pub fn hydrate_islands() {
|
|||
FIRST_CALL.set(false);
|
||||
|
||||
// create a new reactive owner and use it as the root node to run the app
|
||||
let owner = Owner::new_root(Some(Arc::new(HydrateSharedContext::new())));
|
||||
let sc = HydrateSharedContext::new();
|
||||
sc.set_is_hydrating(false); // islands mode starts in "not hydrating"
|
||||
let owner = Owner::new_root(Some(Arc::new(sc)));
|
||||
owner.set();
|
||||
std::mem::forget(owner);
|
||||
}
|
||||
|
|
|
@ -260,11 +260,21 @@ impl ToTokens for Model {
|
|||
let component = if *is_island {
|
||||
quote! {
|
||||
{
|
||||
::leptos::tachys::html::islands::Island::new(
|
||||
#component_id,
|
||||
#component
|
||||
)
|
||||
#island_serialized_props
|
||||
if ::leptos::reactive_graph::owner::Owner::current_shared_context()
|
||||
.map(|sc| sc.get_is_hydrating())
|
||||
.unwrap_or(false) {
|
||||
::leptos::either::Either::Left(
|
||||
#component
|
||||
)
|
||||
} else {
|
||||
::leptos::either::Either::Right(
|
||||
::leptos::tachys::html::islands::Island::new(
|
||||
#component_id,
|
||||
#component
|
||||
)
|
||||
#island_serialized_props
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -285,7 +295,15 @@ impl ToTokens for Model {
|
|||
let wrapped_children = if is_island_with_children {
|
||||
quote! {
|
||||
use leptos::tachys::view::any_view::IntoAny;
|
||||
let children = Box::new(|| ::leptos::tachys::html::islands::IslandChildren::new(children()).into_any());
|
||||
let children = Box::new(|| {
|
||||
let sc = ::leptos::reactive_graph::owner::Owner::current_shared_context().unwrap();
|
||||
let prev = sc.get_is_hydrating();
|
||||
let value = ::leptos::reactive_graph::owner::Owner::with_no_hydration(||
|
||||
::leptos::tachys::html::islands::IslandChildren::new(children()).into_any()
|
||||
);
|
||||
sc.set_is_hydrating(prev);
|
||||
value
|
||||
});
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
|
|
|
@ -274,6 +274,29 @@ impl Owner {
|
|||
|
||||
inner(Box::new(fun))
|
||||
}
|
||||
|
||||
/// Runs the given function, after indicating that the current [`SharedContext`] should /// not handle data created in this function.
|
||||
#[cfg(feature = "hydration")]
|
||||
pub fn with_no_hydration<T>(fun: impl FnOnce() -> T + 'static) -> T {
|
||||
fn inner<T>(fun: Box<dyn FnOnce() -> T>) -> T {
|
||||
let sc = OWNER.with_borrow(|o| {
|
||||
o.as_ref()
|
||||
.and_then(|current| current.shared_context.clone())
|
||||
});
|
||||
match sc {
|
||||
None => fun(),
|
||||
Some(sc) => {
|
||||
let prev = sc.get_is_hydrating();
|
||||
sc.set_is_hydrating(false);
|
||||
let value = fun();
|
||||
sc.set_is_hydrating(prev);
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner(Box::new(fun))
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a function to be run the next time the current owner is cleaned up.
|
||||
|
|
Loading…
Reference in New Issue