mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Get Suspense
/Transition
hydration working
This commit is contained in:
parent
d071a7c1e0
commit
3195ab4ffc
13 changed files with 144 additions and 114 deletions
|
@ -93,13 +93,14 @@ where
|
|||
{
|
||||
use leptos_dom::DynChild;
|
||||
|
||||
let cached_id = HydrationCtx::peak();
|
||||
let _space_for_inner = HydrationCtx::id();
|
||||
let cached_id = HydrationCtx::peek();
|
||||
|
||||
DynChild::new(move || {
|
||||
if context.ready() {
|
||||
leptos_dom::warn!("<Suspense/> ready and continuing from {}", cached_id);
|
||||
HydrationCtx::continue_from(cached_id);
|
||||
let mut id_to_replace = cached_id.clone();
|
||||
id_to_replace.offset -= 1;
|
||||
HydrationCtx::continue_from(id_to_replace);
|
||||
|
||||
child(cx).into_view(cx)
|
||||
} else {
|
||||
|
@ -123,7 +124,7 @@ where
|
|||
use leptos_dom::DynChild;
|
||||
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
let current_id = HydrationCtx::peak();
|
||||
let current_id = HydrationCtx::peek();
|
||||
|
||||
DynChild::new(move || {
|
||||
|
||||
|
@ -138,7 +139,9 @@ where
|
|||
// show the fallback, but also prepare to stream HTML
|
||||
else {
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
cx.register_suspense(context, ¤t_id.to_string(), move || {
|
||||
let mut id_to_replace = current_id.clone();
|
||||
id_to_replace.offset += 1;
|
||||
cx.register_suspense(context, &id_to_replace.to_string(), move || {
|
||||
orig_child(cx)
|
||||
.into_view(cx)
|
||||
.render_to_string(cx)
|
||||
|
@ -146,7 +149,7 @@ where
|
|||
});
|
||||
|
||||
// return the fallback for now, wrapped in fragment identifer
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
fallback().into_view(cx)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -109,13 +109,14 @@ where
|
|||
use std::cell::RefCell;
|
||||
|
||||
let prev_child = RefCell::new(None);
|
||||
let cached_id = HydrationCtx::peak();
|
||||
let _space_for_inner = HydrationCtx::id();
|
||||
let cached_id = HydrationCtx::peek();
|
||||
|
||||
DynChild::new(move || {
|
||||
if context.ready() {
|
||||
leptos_dom::warn!("<Transition/> ready and continuing from {}", cached_id);
|
||||
HydrationCtx::continue_from(cached_id);
|
||||
let mut id_to_replace = cached_id.clone();
|
||||
id_to_replace.offset -= 1;
|
||||
HydrationCtx::continue_from(id_to_replace.clone());
|
||||
|
||||
let current_child = child(cx).into_view(cx);
|
||||
*prev_child.borrow_mut() = Some(current_child.clone());
|
||||
|
@ -152,7 +153,7 @@ where
|
|||
E: IntoView,
|
||||
{
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
let current_id = HydrationCtx::peak();
|
||||
let current_id = HydrationCtx::peek();
|
||||
|
||||
DynChild::new(move || {
|
||||
|
||||
|
@ -167,7 +168,9 @@ where
|
|||
// show the fallback, but also prepare to stream HTML
|
||||
else {
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
cx.register_suspense(context, ¤t_id.to_string(), move || {
|
||||
let mut id_to_replace = current_id.clone();
|
||||
id_to_replace.offset += 1;
|
||||
cx.register_suspense(context, &id_to_replace.to_string(), move || {
|
||||
orig_child(cx)
|
||||
.into_view(cx)
|
||||
.render_to_string(cx)
|
||||
|
@ -175,7 +178,7 @@ where
|
|||
});
|
||||
|
||||
// return the fallback for now, wrapped in fragment identifer
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
fallback().into_view(cx)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ mod each;
|
|||
mod fragment;
|
||||
mod unit;
|
||||
|
||||
use crate::{hydration::HydrationCtx, Comment, IntoView, View};
|
||||
use crate::{hydration::{HydrationCtx, HydrationKey}, Comment, IntoView, View};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::{mount_child, MountKind, Mountable};
|
||||
pub use dyn_child::*;
|
||||
|
@ -51,7 +51,7 @@ pub struct ComponentRepr {
|
|||
pub children: Vec<View>,
|
||||
closing: Comment,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ComponentRepr {
|
||||
|
@ -125,17 +125,17 @@ impl IntoView for ComponentRepr {
|
|||
impl ComponentRepr {
|
||||
/// Creates a new [`Component`].
|
||||
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self::new_with_id(name, HydrationCtx::id())
|
||||
Self::new_with_id(name, HydrationCtx::next_component())
|
||||
}
|
||||
|
||||
/// Creates a new [`Component`] with the given hydration ID.
|
||||
pub fn new_with_id(name: impl Into<Cow<'static, str>>, id: usize) -> Self {
|
||||
pub fn new_with_id(name: impl Into<Cow<'static, str>>, id: HydrationKey) -> Self {
|
||||
let name = name.into();
|
||||
|
||||
let markers = (
|
||||
Comment::new(Cow::Owned(format!("</{name}>")), id, true),
|
||||
Comment::new(Cow::Owned(format!("</{name}>")), &id, true),
|
||||
#[cfg(debug_assertions)]
|
||||
Comment::new(Cow::Owned(format!("<{name}>")), id, false),
|
||||
Comment::new(Cow::Owned(format!("<{name}>")), &id, false),
|
||||
);
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{hydration::HydrationCtx, Comment, IntoView, View};
|
||||
use crate::{hydration::{HydrationCtx, HydrationKey}, Comment, IntoView, View};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::{mount_child, unmount_child, MountKind, Mountable};
|
||||
use leptos_reactive::Scope;
|
||||
|
@ -18,7 +18,7 @@ pub struct DynChildRepr {
|
|||
pub(crate) child: Rc<RefCell<Box<Option<View>>>>,
|
||||
closing: Comment,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DynChildRepr {
|
||||
|
@ -65,9 +65,9 @@ impl DynChildRepr {
|
|||
let id = HydrationCtx::id();
|
||||
|
||||
let markers = (
|
||||
Comment::new(Cow::Borrowed("</DynChild>"), id, true),
|
||||
Comment::new(Cow::Borrowed("</DynChild>"), &id, true),
|
||||
#[cfg(debug_assertions)]
|
||||
Comment::new(Cow::Borrowed("<DynChild>"), id, false),
|
||||
Comment::new(Cow::Borrowed("<DynChild>"), &id, false),
|
||||
);
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View};
|
||||
use crate::{hydration::{HydrationCtx, HydrationKey}, Comment, CoreComponent, IntoView, View};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::{mount_child, MountKind, Mountable, RANGE};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -50,7 +50,7 @@ pub struct EachRepr {
|
|||
pub(crate) children: Rc<RefCell<Vec<Option<EachItem>>>>,
|
||||
closing: Comment,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for EachRepr {
|
||||
|
@ -74,9 +74,9 @@ impl Default for EachRepr {
|
|||
let id = HydrationCtx::id();
|
||||
|
||||
let markers = (
|
||||
Comment::new(Cow::Borrowed("</Each>"), id, true),
|
||||
Comment::new(Cow::Borrowed("</Each>"), &id, true),
|
||||
#[cfg(debug_assertions)]
|
||||
Comment::new(Cow::Borrowed("<Each>"), id, false),
|
||||
Comment::new(Cow::Borrowed("<Each>"), &id, false),
|
||||
);
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -147,7 +147,7 @@ pub(crate) struct EachItem {
|
|||
pub(crate) child: View,
|
||||
closing: Comment,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for EachItem {
|
||||
|
@ -169,9 +169,9 @@ impl EachItem {
|
|||
let id = HydrationCtx::id();
|
||||
|
||||
let markers = (
|
||||
Comment::new(Cow::Borrowed("</EachItem>"), id, true),
|
||||
Comment::new(Cow::Borrowed("</EachItem>"), &id, true),
|
||||
#[cfg(debug_assertions)]
|
||||
Comment::new(Cow::Borrowed("<EachItem>"), id, false),
|
||||
Comment::new(Cow::Borrowed("<EachItem>"), &id, false),
|
||||
);
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -691,7 +691,7 @@ where
|
|||
///
|
||||
/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
/// struct Counter {
|
||||
/// id: usize,
|
||||
/// id: HydrationKey,
|
||||
/// count: RwSignal<i32>
|
||||
/// }
|
||||
///
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use leptos_reactive::Scope;
|
||||
|
||||
use crate::{ComponentRepr, IntoView, View, HydrationCtx};
|
||||
use crate::{ComponentRepr, IntoView, View, HydrationCtx, hydration::HydrationKey};
|
||||
|
||||
/// Trait for converting any iterable into a [`Fragment`].
|
||||
pub trait IntoFragment {
|
||||
|
@ -21,7 +21,7 @@ where
|
|||
/// Represents a group of [`views`](View).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Fragment {
|
||||
id: usize,
|
||||
id: HydrationKey,
|
||||
nodes: Vec<View>
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,13 @@ impl Fragment {
|
|||
Self::new_with_id(HydrationCtx::id(), nodes)
|
||||
}
|
||||
|
||||
/// Creates a new [`Fragment`] from a function that returns [`Vec<Node>`].
|
||||
pub fn lazy(nodes: impl Fn() -> Vec<View>) -> Self {
|
||||
Self::new_with_id(HydrationCtx::id(), nodes())
|
||||
}
|
||||
|
||||
/// Creates a new [`Fragment`] with the given hydration ID from a [`Vec<Node>`].
|
||||
pub fn new_with_id(id: usize, nodes: Vec<View>) -> Self {
|
||||
pub fn new_with_id(id: HydrationKey, nodes: Vec<View>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
nodes
|
||||
|
@ -57,15 +62,15 @@ impl Fragment {
|
|||
}
|
||||
|
||||
/// Returns the fragment's hydration ID.
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
pub fn id(&self) -> &HydrationKey {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoView for Fragment {
|
||||
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "</>", skip_all, fields(children = self.nodes.len())))]
|
||||
fn into_view(self, cx: leptos_reactive::Scope) -> View {
|
||||
let mut frag = ComponentRepr::new_with_id("", self.id);
|
||||
let mut frag = ComponentRepr::new_with_id("", self.id.clone());
|
||||
|
||||
frag.children = self.nodes;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::Mountable;
|
||||
use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View};
|
||||
use crate::{hydration::{HydrationCtx, HydrationKey}, Comment, CoreComponent, IntoView, View};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
|
@ -11,7 +11,7 @@ use wasm_bindgen::JsCast;
|
|||
pub struct UnitRepr {
|
||||
comment: Comment,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for UnitRepr {
|
||||
|
@ -25,7 +25,7 @@ impl Default for UnitRepr {
|
|||
let id = HydrationCtx::id();
|
||||
|
||||
Self {
|
||||
comment: Comment::new("<() />", id, true),
|
||||
comment: Comment::new("<() />", &id, true),
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::hydration::HydrationKey;
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::events::*;
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -70,7 +71,7 @@ pub trait IntoElement: IntoElementBounds {
|
|||
/// A unique `id` that should be generated for each new instance of
|
||||
/// this element, and be consitant for both SSR and CSR.
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
fn hydration_id(&self) -> usize;
|
||||
fn hydration_id(&self) -> &HydrationKey;
|
||||
}
|
||||
|
||||
/// Trait for converting any type which impl [`AsRef<web_sys::Element>`]
|
||||
|
@ -115,7 +116,7 @@ pub struct AnyElement {
|
|||
pub(crate) element: web_sys::HtmlElement,
|
||||
pub(crate) is_void: bool,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) id: usize,
|
||||
pub(crate) id: HydrationKey,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for AnyElement {
|
||||
|
@ -145,8 +146,8 @@ impl IntoElement for AnyElement {
|
|||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
fn hydration_id(&self) -> usize {
|
||||
self.id
|
||||
fn hydration_id(&self) -> &HydrationKey {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +158,7 @@ pub struct Custom {
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
element: web_sys::HtmlElement,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: usize,
|
||||
id: HydrationKey,
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -180,8 +181,8 @@ impl IntoElement for Custom {
|
|||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
fn hydration_id(&self) -> usize {
|
||||
self.id
|
||||
fn hydration_id(&self) -> &HydrationKey {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +294,7 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
element: AnyElement {
|
||||
name: element.name(),
|
||||
is_void: element.is_void(),
|
||||
id: element.hydration_id(),
|
||||
id: element.hydration_id().clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -571,7 +572,7 @@ impl<El: IntoElement> IntoView for HtmlElement<El> {
|
|||
..
|
||||
} = self;
|
||||
|
||||
let id = element.hydration_id();
|
||||
let id = element.hydration_id().clone();
|
||||
|
||||
let mut element = Element::new(element);
|
||||
let children = children;
|
||||
|
@ -611,7 +612,7 @@ pub fn custom<El: IntoElement>(cx: Scope, el: El) -> HtmlElement<Custom> {
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
element: el.get_element().clone(),
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: el.hydration_id(),
|
||||
id: el.hydration_id().clone(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -644,7 +645,7 @@ macro_rules! generate_html_tags {
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
element: web_sys::HtmlElement,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: usize,
|
||||
id: HydrationKey,
|
||||
}
|
||||
|
||||
impl Default for [<$tag:camel $($trailing_)?>] {
|
||||
|
@ -732,8 +733,8 @@ macro_rules! generate_html_tags {
|
|||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
fn hydration_id(&self) -> usize {
|
||||
self.id
|
||||
fn hydration_id(&self) -> &HydrationKey {
|
||||
&self.id
|
||||
}
|
||||
|
||||
generate_html_tags! { @void $($void)? }
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use leptos_reactive::Scope;
|
||||
use std::fmt::Display;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use std::cell::LazyCell;
|
||||
|
@ -10,53 +12,72 @@ use std::cell::LazyCell;
|
|||
#[thread_local]
|
||||
static mut IS_HYDRATING: LazyCell<bool> = LazyCell::new(|| {
|
||||
#[cfg(debug_assertions)]
|
||||
return crate::document().get_element_by_id("_0").is_some()
|
||||
|| crate::document().get_element_by_id("_0o").is_some();
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| crate::document().get_element_by_id("_0-0-0o").is_some();
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
return crate::document().get_element_by_id("_0").is_some();
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some();
|
||||
});
|
||||
|
||||
#[thread_local]
|
||||
static mut ID: usize = 0;
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct HydrationKey {
|
||||
pub previous: String,
|
||||
pub offset: usize
|
||||
}
|
||||
|
||||
#[thread_local]
|
||||
static mut FORCE_HK: bool = false;
|
||||
impl Display for HydrationKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}{}", self.previous, self.offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HydrationKey {
|
||||
fn default() -> Self {
|
||||
Self { previous: "0-".to_string(), offset: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static ID: RefCell<HydrationKey> = Default::default());
|
||||
|
||||
/// Control and utility methods for hydration.
|
||||
pub struct HydrationCtx;
|
||||
|
||||
impl HydrationCtx {
|
||||
/// Get the next `id` without incrementing it.
|
||||
pub fn peak() -> usize {
|
||||
unsafe { ID }
|
||||
pub fn peek() -> HydrationKey {
|
||||
ID.with(|id| id.borrow().clone())
|
||||
}
|
||||
|
||||
/// Increments the current hydration `id` and returns it
|
||||
pub fn id() -> usize {
|
||||
unsafe {
|
||||
let id = ID;
|
||||
|
||||
// Prevent panics on long-running debug builds
|
||||
ID = ID.wrapping_add(1);
|
||||
|
||||
id
|
||||
}
|
||||
pub fn id() -> HydrationKey {
|
||||
ID.with(|id| {
|
||||
let mut id = id.borrow_mut();
|
||||
id.offset = id.offset.wrapping_add(1);
|
||||
id.clone()
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn current_id() -> usize {
|
||||
unsafe { ID }
|
||||
/// Resets the hydration `id` for the next component, and returns it
|
||||
pub fn next_component() -> HydrationKey {
|
||||
ID.with(|id| {
|
||||
let mut id = id.borrow_mut();
|
||||
let offset = id.offset;
|
||||
id.previous.push_str(&offset.to_string());
|
||||
id.previous.push('-');
|
||||
id.offset = 0;
|
||||
id.clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
pub(crate) fn reset_id() {
|
||||
unsafe { ID = 0 };
|
||||
ID.with(|id| *id.borrow_mut() = Default::default());
|
||||
}
|
||||
|
||||
/// Resums hydration from the provided `id`. Usefull for
|
||||
/// `Suspense` and other fancy things.
|
||||
pub fn continue_from(id: usize) {
|
||||
unsafe { ID = id }
|
||||
pub fn continue_from(id: HydrationKey) {
|
||||
ID.with(|i| *i.borrow_mut() = id);
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
|
@ -71,7 +92,7 @@ impl HydrationCtx {
|
|||
unsafe { *IS_HYDRATING }
|
||||
}
|
||||
|
||||
pub(crate) fn to_string(id: usize, closing: bool) -> String {
|
||||
pub(crate) fn to_string(id: &HydrationKey, closing: bool) -> String {
|
||||
#[cfg(debug_assertions)]
|
||||
return format!("_{id}{}", if closing { 'c' } else { 'o' });
|
||||
|
||||
|
@ -82,18 +103,4 @@ impl HydrationCtx {
|
|||
format!("_{id}")
|
||||
}
|
||||
}
|
||||
|
||||
/// All components and elements created after this method is
|
||||
/// called with use `leptos-hk` for their hydration `id`,
|
||||
/// instead of `id`.
|
||||
pub fn start_force_hk() {
|
||||
unsafe { FORCE_HK = true }
|
||||
}
|
||||
|
||||
/// All components and elements created after this method is
|
||||
/// called with use `id` by default for their hydration `id`,
|
||||
/// instead of `leptos-hk`.
|
||||
pub fn stop_force_hk() {
|
||||
unsafe { FORCE_HK = false }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ pub use events::typed as ev;
|
|||
pub use helpers::*;
|
||||
pub use html::*;
|
||||
pub use hydration::HydrationCtx;
|
||||
use hydration::HydrationKey;
|
||||
pub use js_sys;
|
||||
use leptos_reactive::Scope;
|
||||
pub use logging::*;
|
||||
|
@ -150,7 +151,7 @@ cfg_if! {
|
|||
attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
|
||||
children: Vec<View>,
|
||||
prerendered: Option<Cow<'static, str>>,
|
||||
id: usize,
|
||||
id: HydrationKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Element {
|
||||
|
@ -245,7 +246,7 @@ impl Element {
|
|||
is_void: el.is_void(),
|
||||
attrs: Default::default(),
|
||||
children: Default::default(),
|
||||
id: el.hydration_id(),
|
||||
id: el.hydration_id().clone(),
|
||||
prerendered: None
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +264,7 @@ impl Element {
|
|||
is_void: el.is_void(),
|
||||
attrs: Default::default(),
|
||||
children: Default::default(),
|
||||
id: el.hydration_id(),
|
||||
id: el.hydration_id().clone(),
|
||||
prerendered: Some(html.into()),
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +280,7 @@ struct Comment {
|
|||
impl Comment {
|
||||
fn new(
|
||||
content: impl Into<Cow<'static, str>>,
|
||||
id: usize,
|
||||
id: &HydrationKey,
|
||||
closing: bool,
|
||||
) -> Self {
|
||||
let content = content.into();
|
||||
|
|
|
@ -182,9 +182,9 @@ impl View {
|
|||
cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
format!(r#"<template id="{}"></template>{}<template id="{}"></template>"#,
|
||||
HydrationCtx::to_string(node.id, false),
|
||||
HydrationCtx::to_string(&node.id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(node.id, true)
|
||||
HydrationCtx::to_string(&node.id, true)
|
||||
).into()
|
||||
} else {
|
||||
format!(
|
||||
|
@ -198,11 +198,11 @@ impl View {
|
|||
View::CoreComponent(node) => {
|
||||
let (id, wrap, content) = match node {
|
||||
CoreComponent::Unit(u) => (
|
||||
u.id,
|
||||
u.id.clone(),
|
||||
false,
|
||||
Box::new(move || format!(
|
||||
"<template id={}></template>",
|
||||
HydrationCtx::to_string(u.id, true)
|
||||
HydrationCtx::to_string(&u.id, true)
|
||||
)
|
||||
.into()) as Box<dyn FnOnce() -> Cow<'static, str>>,
|
||||
),
|
||||
|
@ -251,9 +251,9 @@ impl View {
|
|||
return format!(
|
||||
"<template id=\"{}\"></template>{}<template \
|
||||
id=\"{}\"></template>",
|
||||
HydrationCtx::to_string(id, false),
|
||||
HydrationCtx::to_string(&id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(id, true),
|
||||
HydrationCtx::to_string(&id, true),
|
||||
);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
|
@ -275,15 +275,15 @@ impl View {
|
|||
if #[cfg(debug_assertions)] {
|
||||
format!(
|
||||
r#"<template id="{}"></template>{}<template id="{}"></template>"#,
|
||||
HydrationCtx::to_string(id, false),
|
||||
HydrationCtx::to_string(&id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(id, true),
|
||||
HydrationCtx::to_string(&id, true),
|
||||
).into()
|
||||
} else {
|
||||
format!(
|
||||
r#"{}<template id="{}"></template>"#,
|
||||
content(),
|
||||
HydrationCtx::to_string(id, true)
|
||||
HydrationCtx::to_string(&id, true)
|
||||
).into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ pub(crate) fn render_view(cx: &Ident, nodes: &[Node], mode: Mode) -> TokenStream
|
|||
} else if nodes.len() == 1 {
|
||||
node_to_tokens(cx, &nodes[0])
|
||||
} else {
|
||||
fragment_to_tokens(cx, Span::call_site(), nodes)
|
||||
fragment_to_tokens(cx, Span::call_site(), nodes, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ fn set_class_attribute_ssr(
|
|||
}
|
||||
}
|
||||
|
||||
fn fragment_to_tokens(cx: &Ident, span: Span, nodes: &[Node]) -> TokenStream {
|
||||
fn fragment_to_tokens(cx: &Ident, span: Span, nodes: &[Node], lazy: bool) -> TokenStream {
|
||||
let nodes = nodes.iter().map(|node| {
|
||||
let node = node_to_tokens(cx, node);
|
||||
|
||||
|
@ -483,18 +483,28 @@ fn fragment_to_tokens(cx: &Ident, span: Span, nodes: &[Node]) -> TokenStream {
|
|||
#node.into_view(#cx)
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
{
|
||||
leptos::Fragment::new(vec![
|
||||
#(#nodes),*
|
||||
])
|
||||
if lazy {
|
||||
quote! {
|
||||
{
|
||||
leptos::Fragment::lazy(|| vec![
|
||||
#(#nodes),*
|
||||
])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
{
|
||||
leptos::Fragment::new(vec![
|
||||
#(#nodes),*
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn node_to_tokens(cx: &Ident, node: &Node) -> TokenStream {
|
||||
match node {
|
||||
Node::Fragment(fragment) => fragment_to_tokens(cx, Span::call_site(), &fragment.children),
|
||||
Node::Fragment(fragment) => fragment_to_tokens(cx, Span::call_site(), &fragment.children, false),
|
||||
Node::Comment(_) | Node::Doctype(_) => quote! {},
|
||||
Node::Text(node) => {
|
||||
let value = node.value.as_ref();
|
||||
|
@ -533,7 +543,7 @@ fn element_to_tokens(cx: &Ident, node: &NodeElement) -> TokenStream {
|
|||
let children = node.children.iter().map(|node| {
|
||||
let child = match node {
|
||||
Node::Fragment(fragment) => {
|
||||
fragment_to_tokens(cx, Span::call_site(), &fragment.children)
|
||||
fragment_to_tokens(cx, Span::call_site(), &fragment.children, false)
|
||||
}
|
||||
Node::Text(node) => {
|
||||
let span = node.value.span();
|
||||
|
@ -644,7 +654,7 @@ fn component_to_tokens(cx: &Ident, node: &NodeElement) -> TokenStream {
|
|||
let children = if node.children.is_empty() {
|
||||
quote! {}
|
||||
} else {
|
||||
let children = fragment_to_tokens(cx, span, &node.children);
|
||||
let children = fragment_to_tokens(cx, span, &node.children, true);
|
||||
quote! { .children(Box::new(move |#cx| #children)) }
|
||||
};
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ pub fn Routes(
|
|||
});
|
||||
|
||||
Fragment::new_with_id(
|
||||
frag.id(),
|
||||
frag.id().clone(),
|
||||
vec![(move || root.get()).into_view(cx)]
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue