Merge pull request #811 from Demonthos/implement-hydration
Implement Hydration
This commit is contained in:
6 files changed
+280
-168
No files matched your search
@@ -73,7 +73,8 @@ pub use crate::innerlude::{
|
|||||||
fc_to_builder, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, CapturedError,
|
fc_to_builder, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, CapturedError,
|
||||||
Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, LazyNodes, Mutation,
|
Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, LazyNodes, Mutation,
|
||||||
Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, SuspenseContext,
|
Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, SuspenseContext,
|
||||||
TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VText, VirtualDom,
|
TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText,
|
||||||
|
VirtualDom,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The purpose of this module is to alleviate imports of many common types
|
/// The purpose of this module is to alleviate imports of many common types
|
||||||
|
|||||||
@@ -88,4 +88,4 @@ dioxus = { path = "../dioxus", version = "0.3.0" }
|
|||||||
wasm-bindgen-test = "0.3.29"
|
wasm-bindgen-test = "0.3.29"
|
||||||
dioxus-ssr = { path = "../ssr", version = "0.3.0"}
|
dioxus-ssr = { path = "../ssr", version = "0.3.0"}
|
||||||
wasm-logger = "0.2.0"
|
wasm-logger = "0.2.0"
|
||||||
dioxus-web = { path = "." }
|
dioxus-web = { path = ".", features = ["hydrate"] }
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
/// dioxus_web::launch(App, Config::new().hydrate(true).root_name("myroot"))
|
/// dioxus_web::launch(App, Config::new().hydrate(true).root_name("myroot"))
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
pub(crate) hydrate: bool,
|
pub(crate) hydrate: bool,
|
||||||
pub(crate) rootname: String,
|
pub(crate) rootname: String,
|
||||||
pub(crate) cached_strings: Vec<String>,
|
pub(crate) cached_strings: Vec<String>,
|
||||||
@@ -17,6 +18,7 @@ pub struct Config {
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
hydrate: false,
|
hydrate: false,
|
||||||
rootname: "main".to_string(),
|
rootname: "main".to_string(),
|
||||||
cached_strings: Vec::new(),
|
cached_strings: Vec::new(),
|
||||||
@@ -33,6 +35,7 @@ impl Config {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
/// Enable SSR hydration
|
/// Enable SSR hydration
|
||||||
///
|
///
|
||||||
/// This enables Dioxus to pick up work from a pre-renderd HTML file. Hydration will completely skip over any async
|
/// This enables Dioxus to pick up work from a pre-renderd HTML file. Hydration will completely skip over any async
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ use crate::Config;
|
|||||||
|
|
||||||
pub struct WebsysDom {
|
pub struct WebsysDom {
|
||||||
document: Document,
|
document: Document,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) root: Element,
|
||||||
templates: FxHashMap<String, u32>,
|
templates: FxHashMap<String, u32>,
|
||||||
max_template_id: u32,
|
max_template_id: u32,
|
||||||
interpreter: Channel,
|
pub(crate) interpreter: Channel,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UiEvent {
|
pub struct UiEvent {
|
||||||
@@ -72,10 +74,14 @@ impl WebsysDom {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dioxus_interpreter_js::initilize(root.unchecked_into(), handler.as_ref().unchecked_ref());
|
dioxus_interpreter_js::initilize(
|
||||||
|
root.clone().unchecked_into(),
|
||||||
|
handler.as_ref().unchecked_ref(),
|
||||||
|
);
|
||||||
handler.forget();
|
handler.forget();
|
||||||
Self {
|
Self {
|
||||||
document,
|
document,
|
||||||
|
root,
|
||||||
interpreter,
|
interpreter,
|
||||||
templates: FxHashMap::default(),
|
templates: FxHashMap::default(),
|
||||||
max_template_id: 0,
|
max_template_id: 0,
|
||||||
|
|||||||
+30
-32
@@ -62,6 +62,8 @@ mod cache;
|
|||||||
mod cfg;
|
mod cfg;
|
||||||
mod dom;
|
mod dom;
|
||||||
mod hot_reload;
|
mod hot_reload;
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
|
mod rehydrate;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
// Currently disabled since it actually slows down immediate rendering
|
// Currently disabled since it actually slows down immediate rendering
|
||||||
@@ -179,17 +181,40 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
|
|||||||
wasm_bindgen::intern(s);
|
wasm_bindgen::intern(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _should_hydrate = cfg.hydrate;
|
|
||||||
|
|
||||||
let (tx, mut rx) = futures_channel::mpsc::unbounded();
|
let (tx, mut rx) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
|
let should_hydrate = cfg.hydrate;
|
||||||
|
#[cfg(not(feature = "hydrate"))]
|
||||||
|
let should_hydrate = false;
|
||||||
|
|
||||||
let mut websys_dom = dom::WebsysDom::new(cfg, tx);
|
let mut websys_dom = dom::WebsysDom::new(cfg, tx);
|
||||||
|
|
||||||
log::info!("rebuilding app");
|
log::info!("rebuilding app");
|
||||||
|
|
||||||
// if should_hydrate {
|
if should_hydrate {
|
||||||
// } else {
|
#[cfg(feature = "hydrate")]
|
||||||
{
|
{
|
||||||
|
// todo: we need to split rebuild and initialize into two phases
|
||||||
|
// it's a waste to produce edits just to get the vdom loaded
|
||||||
|
|
||||||
|
let templates = dom.rebuild().templates;
|
||||||
|
websys_dom.load_templates(&templates);
|
||||||
|
|
||||||
|
if let Err(err) = websys_dom.rehydrate(&dom) {
|
||||||
|
log::error!(
|
||||||
|
"Rehydration failed {:?}. Rebuild DOM into element from scratch",
|
||||||
|
&err
|
||||||
|
);
|
||||||
|
websys_dom.root.set_text_content(None);
|
||||||
|
|
||||||
|
let edits = dom.rebuild();
|
||||||
|
|
||||||
|
websys_dom.load_templates(&edits.templates);
|
||||||
|
websys_dom.apply_edits(edits.edits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let edits = dom.rebuild();
|
let edits = dom.rebuild();
|
||||||
|
|
||||||
websys_dom.load_templates(&edits.templates);
|
websys_dom.load_templates(&edits.templates);
|
||||||
@@ -249,30 +274,3 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
|
|||||||
websys_dom.apply_edits(edits.edits);
|
websys_dom.apply_edits(edits.edits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if should_hydrate {
|
|
||||||
// // todo: we need to split rebuild and initialize into two phases
|
|
||||||
// // it's a waste to produce edits just to get the vdom loaded
|
|
||||||
// let _ = dom.rebuild();
|
|
||||||
|
|
||||||
// #[cfg(feature = "hydrate")]
|
|
||||||
// #[allow(unused_variables)]
|
|
||||||
// if let Err(err) = websys_dom.rehydrate(&dom) {
|
|
||||||
// log::error!(
|
|
||||||
// "Rehydration failed {:?}. Rebuild DOM into element from scratch",
|
|
||||||
// &err
|
|
||||||
// );
|
|
||||||
|
|
||||||
// websys_dom.root.set_text_content(None);
|
|
||||||
|
|
||||||
// // errrrr we should split rebuild into two phases
|
|
||||||
// // one that initializes things and one that produces edits
|
|
||||||
// let edits = dom.rebuild();
|
|
||||||
|
|
||||||
// websys_dom.apply_edits(edits.edits);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// let edits = dom.rebuild();
|
|
||||||
// websys_dom.apply_edits(edits.template_mutations);
|
|
||||||
// websys_dom.apply_edits(edits.edits);
|
|
||||||
// }
|
|
||||||
+236
-132
@@ -1,9 +1,13 @@
|
|||||||
use crate::dom::WebsysDom;
|
use crate::dom::WebsysDom;
|
||||||
use dioxus_core::{VNode, VirtualDom};
|
use dioxus_core::{
|
||||||
|
AttributeValue, DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VPlaceholder, VText,
|
||||||
|
VirtualDom,
|
||||||
|
};
|
||||||
|
use dioxus_html::event_bubbles;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::{Comment, Element, Node, Text};
|
use web_sys::{Comment, Node};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum RehydrationError {
|
pub enum RehydrationError {
|
||||||
NodeTypeMismatch,
|
NodeTypeMismatch,
|
||||||
NodeNotFound,
|
NodeNotFound,
|
||||||
@@ -11,163 +15,263 @@ pub enum RehydrationError {
|
|||||||
}
|
}
|
||||||
use RehydrationError::*;
|
use RehydrationError::*;
|
||||||
|
|
||||||
|
fn set_node(hydrated: &mut Vec<bool>, id: ElementId, node: Node) {
|
||||||
|
let idx = id.0;
|
||||||
|
if idx >= hydrated.len() {
|
||||||
|
hydrated.resize(idx + 1, false);
|
||||||
|
}
|
||||||
|
if !hydrated[idx] {
|
||||||
|
dioxus_interpreter_js::set_node(idx as u32, node);
|
||||||
|
hydrated[idx] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WebsysDom {
|
impl WebsysDom {
|
||||||
// we're streaming in patches, but the nodes already exist
|
// we're streaming in patches, but the nodes already exist
|
||||||
// so we're just going to write the correct IDs to the node and load them in
|
// so we're just going to write the correct IDs to the node and load them in
|
||||||
pub fn rehydrate(&mut self, dom: &VirtualDom) -> Result<(), RehydrationError> {
|
pub fn rehydrate(&mut self, dom: &VirtualDom) -> Result<(), RehydrationError> {
|
||||||
let root = self
|
let mut root = self
|
||||||
.root
|
.root
|
||||||
.clone()
|
.clone()
|
||||||
.dyn_into::<Node>()
|
.dyn_into::<Node>()
|
||||||
.map_err(|_| NodeTypeMismatch)?;
|
.map_err(|_| NodeTypeMismatch)?
|
||||||
|
.first_child()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
|
||||||
let root_scope = dom.base_scope();
|
let root_scope = dom.base_scope();
|
||||||
let root_node = root_scope.root_node();
|
|
||||||
|
|
||||||
let mut nodes = vec![root];
|
let mut hydrated = vec![true];
|
||||||
let mut counter = vec![0];
|
|
||||||
|
|
||||||
let mut last_node_was_text = false;
|
let mut last_node_was_static_text = false;
|
||||||
|
|
||||||
todo!()
|
// Recursively rehydrate the dom from the VirtualDom
|
||||||
// // Recursively rehydrate the dom from the VirtualDom
|
self.rehydrate_scope(
|
||||||
// self.rehydrate_single(
|
root_scope,
|
||||||
// &mut nodes,
|
&mut root,
|
||||||
// &mut counter,
|
&mut hydrated,
|
||||||
// dom,
|
dom,
|
||||||
// root_node,
|
&mut last_node_was_static_text,
|
||||||
// &mut last_node_was_text,
|
)?;
|
||||||
// )
|
|
||||||
|
self.interpreter.flush();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rehydrate_single(
|
fn rehydrate_scope(
|
||||||
&mut self,
|
&mut self,
|
||||||
nodes: &mut Vec<Node>,
|
scope: &ScopeState,
|
||||||
place: &mut Vec<u32>,
|
current_child: &mut Result<Node, RehydrationError>,
|
||||||
|
hydrated: &mut Vec<bool>,
|
||||||
dom: &VirtualDom,
|
dom: &VirtualDom,
|
||||||
node: &VNode,
|
last_node_was_static_text: &mut bool,
|
||||||
last_node_was_text: &mut bool,
|
) -> Result<(), RehydrationError> {
|
||||||
|
let vnode = match scope.root_node() {
|
||||||
|
dioxus_core::RenderReturn::Ready(ready) => ready,
|
||||||
|
_ => return Err(VNodeNotInitialized),
|
||||||
|
};
|
||||||
|
self.rehydrate_vnode(
|
||||||
|
current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
vnode,
|
||||||
|
last_node_was_static_text,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rehydrate_vnode(
|
||||||
|
&mut self,
|
||||||
|
current_child: &mut Result<Node, RehydrationError>,
|
||||||
|
hydrated: &mut Vec<bool>,
|
||||||
|
dom: &VirtualDom,
|
||||||
|
vnode: &VNode,
|
||||||
|
last_node_was_static_text: &mut bool,
|
||||||
|
) -> Result<(), RehydrationError> {
|
||||||
|
for (i, root) in vnode.template.get().roots.iter().enumerate() {
|
||||||
|
// make sure we set the root node ids even if the node is not dynamic
|
||||||
|
set_node(
|
||||||
|
hydrated,
|
||||||
|
vnode.root_ids.get(i).ok_or(VNodeNotInitialized)?,
|
||||||
|
current_child.clone()?,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.rehydrate_template_node(
|
||||||
|
current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
vnode,
|
||||||
|
root,
|
||||||
|
last_node_was_static_text,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rehydrate_template_node(
|
||||||
|
&mut self,
|
||||||
|
current_child: &mut Result<Node, RehydrationError>,
|
||||||
|
hydrated: &mut Vec<bool>,
|
||||||
|
dom: &VirtualDom,
|
||||||
|
vnode: &VNode,
|
||||||
|
node: &TemplateNode,
|
||||||
|
last_node_was_static_text: &mut bool,
|
||||||
) -> Result<(), RehydrationError> {
|
) -> Result<(), RehydrationError> {
|
||||||
match node {
|
match node {
|
||||||
VNode::Text(t) => {
|
TemplateNode::Element {
|
||||||
let node_id = t.id.get().ok_or(VNodeNotInitialized)?;
|
children, attrs, ..
|
||||||
|
} => {
|
||||||
let cur_place = place.last_mut().unwrap();
|
let mut mounted_id = None;
|
||||||
|
for attr in *attrs {
|
||||||
// skip over the comment element
|
if let dioxus_core::TemplateAttribute::Dynamic { id } = attr {
|
||||||
if *last_node_was_text {
|
let attribute = &vnode.dynamic_attrs[*id];
|
||||||
if cfg!(debug_assertions) {
|
let value = &attribute.value;
|
||||||
let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
|
let id = attribute.mounted_element.get();
|
||||||
let node_text = node.dyn_into::<Comment>().unwrap();
|
mounted_id = Some(id);
|
||||||
assert_eq!(node_text.data(), "spacer");
|
let name = attribute.name;
|
||||||
|
if let AttributeValue::Listener(_) = value {
|
||||||
|
self.interpreter.new_event_listener(
|
||||||
|
&name[2..],
|
||||||
|
id.0 as u32,
|
||||||
|
event_bubbles(name) as u8,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*cur_place += 1;
|
|
||||||
}
|
}
|
||||||
|
if let Some(id) = mounted_id {
|
||||||
|
set_node(hydrated, id, current_child.clone()?);
|
||||||
|
}
|
||||||
|
if !children.is_empty() {
|
||||||
|
let mut children_current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.first_child()
|
||||||
|
.ok_or(NodeNotFound)?
|
||||||
|
.dyn_into::<Node>()
|
||||||
|
.map_err(|_| NodeTypeMismatch);
|
||||||
|
for child in *children {
|
||||||
|
self.rehydrate_template_node(
|
||||||
|
&mut children_current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
vnode,
|
||||||
|
child,
|
||||||
|
last_node_was_static_text,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
*last_node_was_static_text = false;
|
||||||
|
}
|
||||||
|
TemplateNode::Text { .. } => {
|
||||||
|
// if the last node was static text, it got merged with this one
|
||||||
|
if !*last_node_was_static_text {
|
||||||
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
}
|
||||||
|
*last_node_was_static_text = true;
|
||||||
|
}
|
||||||
|
TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
|
||||||
|
self.rehydrate_dynamic_node(
|
||||||
|
current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
&vnode.dynamic_nodes[*id],
|
||||||
|
last_node_was_static_text,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let node = nodes
|
fn rehydrate_dynamic_node(
|
||||||
.last()
|
&mut self,
|
||||||
.unwrap()
|
current_child: &mut Result<Node, RehydrationError>,
|
||||||
.child_nodes()
|
hydrated: &mut Vec<bool>,
|
||||||
.get(*cur_place)
|
dom: &VirtualDom,
|
||||||
.ok_or(NodeNotFound)?;
|
dynamic: &DynamicNode,
|
||||||
|
last_node_was_static_text: &mut bool,
|
||||||
let _text_el = node.dyn_ref::<Text>().ok_or(NodeTypeMismatch)?;
|
) -> Result<(), RehydrationError> {
|
||||||
|
match dynamic {
|
||||||
// in debug we make sure the text is the same
|
dioxus_core::DynamicNode::Text(VText { id, .. }) => {
|
||||||
|
// skip comment separator before node
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let contents = _text_el.node_value().unwrap();
|
assert!(current_child
|
||||||
assert_eq!(t.text, contents);
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.has_type::<Comment>());
|
||||||
}
|
}
|
||||||
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
|
||||||
*last_node_was_text = true;
|
set_node(
|
||||||
|
hydrated,
|
||||||
self.interpreter.SetNode(node_id.0, node);
|
id.get().ok_or(VNodeNotInitialized)?,
|
||||||
|
current_child.clone()?,
|
||||||
*cur_place += 1;
|
);
|
||||||
}
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
VNode::Element(vel) => {
|
.map_err(|e| *e)?
|
||||||
let node_id = vel.id.get().ok_or(VNodeNotInitialized)?;
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
let cur_place = place.last_mut().unwrap();
|
|
||||||
|
|
||||||
let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
|
|
||||||
|
|
||||||
self.interpreter.SetNode(node_id.0, node.clone());
|
|
||||||
|
|
||||||
*cur_place += 1;
|
|
||||||
|
|
||||||
nodes.push(node.clone());
|
|
||||||
|
|
||||||
place.push(0);
|
|
||||||
|
|
||||||
// we cant have the last node be text
|
|
||||||
let mut last_node_was_text = false;
|
|
||||||
for child in vel.children {
|
|
||||||
self.rehydrate_single(nodes, place, dom, child, &mut last_node_was_text)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for listener in vel.listeners {
|
|
||||||
let id = listener.mounted_node.get().unwrap();
|
|
||||||
self.interpreter.NewEventListener(
|
|
||||||
listener.event,
|
|
||||||
Some(id.as_u64()),
|
|
||||||
self.handler.as_ref().unchecked_ref(),
|
|
||||||
event_bubbles(listener.event),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !vel.listeners.is_empty() {
|
|
||||||
use smallstr::SmallString;
|
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
// 8 digits is enough, yes?
|
|
||||||
// 12 million nodes in one page?
|
|
||||||
let mut s: SmallString<[u8; 8]> = smallstr::SmallString::new();
|
|
||||||
write!(s, "{}", node_id).unwrap();
|
|
||||||
|
|
||||||
node.dyn_ref::<Element>()
|
|
||||||
.unwrap()
|
|
||||||
.set_attribute("dioxus-id", s.as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
place.pop();
|
|
||||||
nodes.pop();
|
|
||||||
|
|
||||||
|
// skip comment separator after node
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let el = node.dyn_ref::<Element>().unwrap();
|
assert!(current_child
|
||||||
let name = el.tag_name().to_lowercase();
|
.as_mut()
|
||||||
assert_eq!(name, vel.tag);
|
.map_err(|e| *e)?
|
||||||
|
.has_type::<Comment>());
|
||||||
|
}
|
||||||
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
|
||||||
|
*last_node_was_static_text = false;
|
||||||
|
}
|
||||||
|
dioxus_core::DynamicNode::Placeholder(VPlaceholder { id, .. }) => {
|
||||||
|
set_node(
|
||||||
|
hydrated,
|
||||||
|
id.get().ok_or(VNodeNotInitialized)?,
|
||||||
|
current_child.clone()?,
|
||||||
|
);
|
||||||
|
*current_child = current_child
|
||||||
|
.as_mut()
|
||||||
|
.map_err(|e| *e)?
|
||||||
|
.next_sibling()
|
||||||
|
.ok_or(NodeNotFound);
|
||||||
|
*last_node_was_static_text = false;
|
||||||
|
}
|
||||||
|
dioxus_core::DynamicNode::Component(comp) => {
|
||||||
|
let scope = comp.scope.get().ok_or(VNodeNotInitialized)?;
|
||||||
|
self.rehydrate_scope(
|
||||||
|
dom.get_scope(scope).unwrap(),
|
||||||
|
current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
last_node_was_static_text,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
dioxus_core::DynamicNode::Fragment(fragment) => {
|
||||||
|
for vnode in *fragment {
|
||||||
|
self.rehydrate_vnode(
|
||||||
|
current_child,
|
||||||
|
hydrated,
|
||||||
|
dom,
|
||||||
|
vnode,
|
||||||
|
last_node_was_static_text,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VNode::Placeholder(el) => {
|
|
||||||
let node_id = el.id.get().ok_or(VNodeNotInitialized)?;
|
|
||||||
|
|
||||||
let cur_place = place.last_mut().unwrap();
|
|
||||||
let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
|
|
||||||
|
|
||||||
self.interpreter.SetNode(node_id.0, node);
|
|
||||||
|
|
||||||
// self.nodes[node_id.0] = Some(node);
|
|
||||||
|
|
||||||
*cur_place += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Fragment(el) => {
|
|
||||||
for el in el.children {
|
|
||||||
self.rehydrate_single(nodes, place, dom, el, last_node_was_text)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VNode::Component(el) => {
|
|
||||||
let scope = dom.get_scope(el.scope.get().unwrap()).unwrap();
|
|
||||||
let node = scope.root_node();
|
|
||||||
todo!()
|
|
||||||
// self.rehydrate_single(nodes, place, dom, node, last_node_was_text)?;
|
|
||||||
}
|
|
||||||
VNode::TemplateRef(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user