Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify SsrNode and HydrateNode codegen in view! macro #392

Merged
merged 4 commits into from
Mar 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 20 additions & 23 deletions packages/sycamore-macro/src/view/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,22 +131,7 @@ impl Codegen {
};
let marker_or_none = marker_is_some.then(|| marker.clone()).unwrap_or_default();

// If __el is a HydrateNode, use get_next_marker as initial node value.
let initial = if cfg!(feature = "experimental-hydrate") {
quote! {
if let ::std::option::Option::Some(__el)
= <dyn ::std::any::Any>::downcast_ref::<::sycamore::generic_node::HydrateNode>(&__el) {
let __initial = ::sycamore::utils::hydrate::web::get_next_marker(&__el.inner_element());
// Do not drop the HydrateNode because it will be cast into a GenericNode.
let __initial = ::std::mem::ManuallyDrop::new(__initial);
// SAFETY: This is safe because we already checked that the type is HydrateNode.
// __initial is wrapped inside ManuallyDrop to prevent double drop.
unsafe { ::std::ptr::read(&__initial as *const _ as *const _) }
} else { ::std::option::Option::None }
}
} else {
quote! { ::std::option::Option::None }
};
let initial = quote! { ::sycamore::utils::initial_node(&__el) };
let ssr_markers = quote! {
::sycamore::generic_node::GenericNode::append_child(
&__el,
Expand All @@ -161,15 +146,21 @@ impl Codegen {
let comp = self.component(comp);
let quoted = quote! {
#marker
::sycamore::utils::render::insert(#ctx, &__el, #comp, #initial, __marker, #multi);
::sycamore::utils::render::insert(#ctx, &__el, __comp, __initial, __marker, #multi);
};
codegen_ssr_markers.then(|| quote! {
let __comp = #comp;
let __initial = #initial;
if ::std::any::Any::type_id(&__el) == ::std::any::TypeId::of::<::sycamore::generic_node::SsrNode>() {
#ssr_markers
::sycamore::utils::render::insert(#ctx, &__el, #comp, #initial, Some(&__end_marker), #multi);
::sycamore::utils::render::insert(#ctx, &__el, __comp, __initial, Some(&__end_marker), #multi);
#marker_or_none
} else { #quoted }
}).unwrap_or(quoted)
}).unwrap_or(quote! {
let __comp = #comp;
let __initial = #initial;
#quoted
})
}
ViewNode::Dyn(d @ Dyn { value}) => {
let needs_ctx = d.needs_ctx(&self.ctx.to_string());
Expand All @@ -187,17 +178,23 @@ impl Codegen {
};
let quoted = quote! {
#marker
::sycamore::utils::render::insert(#ctx, &__el, #view_quoted, #initial, __marker, #multi);
::sycamore::utils::render::insert(#ctx, &__el, __view, __initial, __marker, #multi);
};
codegen_ssr_markers.then(|| quote!{
codegen_ssr_markers.then(|| quote! {
let __view = #view_quoted;
let __initial = #initial;
if ::std::any::Any::type_id(&__el) == ::std::any::TypeId::of::<::sycamore::generic_node::SsrNode>() {
#ssr_markers
::sycamore::utils::render::insert(
#ctx, &__el, #view_quoted, #initial, Some(&__end_marker), #multi
#ctx, &__el, __view, __initial, Some(&__end_marker), #multi
);
#marker_or_none
} else { #quoted }
}).unwrap_or(quoted)
}).unwrap_or(quote! {
let __view = #view_quoted;
let __initial = #initial;
#quoted
})
},
_ => unreachable!("only component and dyn node can be dynamic"),
});
Expand Down
28 changes: 28 additions & 0 deletions packages/sycamore/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@
//! This API is considered implementation details and should not at any time be considered stable.
//! The API can change without warning and without a semver compatible release.

use crate::generic_node::GenericNode;
use crate::prelude::View;

#[cfg(feature = "experimental-hydrate")]
pub mod hydrate;
pub mod render;

/// If `el` is a `HydrateNode`, use `get_next_marker` to get the initial node value.
pub fn initial_node<G: GenericNode>(_el: &G) -> Option<View<G>> {
#[cfg(feature = "experimental-hydrate")]
{
use crate::generic_node::HydrateNode;
use std::any::Any;
use std::mem::ManuallyDrop;
use std::ptr;
if let Some(el) = <dyn Any>::downcast_ref::<HydrateNode>(_el) {
let initial = hydrate::web::get_next_marker(&el.inner_element());
// Do not drop the HydrateNode because it will be cast into a GenericNode.
let initial = ManuallyDrop::new(initial);
// SAFETY: This is safe because we already checked that the type is HydrateNode.
// initial is wrapped inside ManuallyDrop to prevent double drop.
unsafe { ptr::read(&initial as *const _ as *const _) }
} else {
None
}
}
#[cfg(not(feature = "experimental-hydrate"))]
{
None
}
}