rehydrate.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. use crate::dom::WebsysDom;
  2. use dioxus_core::{VNode, VirtualDom};
  3. use wasm_bindgen::JsCast;
  4. use web_sys::{Comment, Element, Node, Text};
  5. #[derive(Debug)]
  6. pub enum RehydrationError {
  7. NodeTypeMismatch,
  8. NodeNotFound,
  9. VNodeNotInitialized,
  10. }
  11. use RehydrationError::*;
  12. impl WebsysDom {
  13. // we're streaming in patches, but the nodes already exist
  14. // so we're just going to write the correct IDs to the node and load them in
  15. pub fn rehydrate(&mut self, dom: &VirtualDom) -> Result<(), RehydrationError> {
  16. let root = self
  17. .root
  18. .clone()
  19. .dyn_into::<Node>()
  20. .map_err(|_| NodeTypeMismatch)?;
  21. let root_scope = dom.base_scope();
  22. let root_node = root_scope.root_node();
  23. let mut nodes = vec![root];
  24. let mut counter = vec![0];
  25. let mut last_node_was_text = false;
  26. // Recursively rehydrate the dom from the VirtualDom
  27. self.rehydrate_single(
  28. &mut nodes,
  29. &mut counter,
  30. dom,
  31. root_node,
  32. &mut last_node_was_text,
  33. )
  34. }
  35. fn rehydrate_single(
  36. &mut self,
  37. nodes: &mut Vec<Node>,
  38. place: &mut Vec<u32>,
  39. dom: &VirtualDom,
  40. node: &VNode,
  41. last_node_was_text: &mut bool,
  42. ) -> Result<(), RehydrationError> {
  43. match node {
  44. VNode::Text(t) => {
  45. let node_id = t.id.get().ok_or(VNodeNotInitialized)?;
  46. let cur_place = place.last_mut().unwrap();
  47. // skip over the comment element
  48. if *last_node_was_text {
  49. if cfg!(debug_assertions) {
  50. let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
  51. let node_text = node.dyn_into::<Comment>().unwrap();
  52. assert_eq!(node_text.data(), "spacer");
  53. }
  54. *cur_place += 1;
  55. }
  56. let node = nodes
  57. .last()
  58. .unwrap()
  59. .child_nodes()
  60. .get(*cur_place)
  61. .ok_or(NodeNotFound)?;
  62. let _text_el = node.dyn_ref::<Text>().ok_or(NodeTypeMismatch)?;
  63. // in debug we make sure the text is the same
  64. if cfg!(debug_assertions) {
  65. let contents = _text_el.node_value().unwrap();
  66. assert_eq!(t.text, contents);
  67. }
  68. *last_node_was_text = true;
  69. self.interpreter.set_node(node_id.0, node);
  70. // self.nodes[node_id.0] = Some(node);
  71. *cur_place += 1;
  72. }
  73. VNode::Element(vel) => {
  74. let node_id = vel.id.get().ok_or(VNodeNotInitialized)?;
  75. let cur_place = place.last_mut().unwrap();
  76. let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
  77. use smallstr::SmallString;
  78. use std::fmt::Write;
  79. // 8 digits is enough, yes?
  80. // 12 million nodes in one page?
  81. let mut s: SmallString<[u8; 8]> = smallstr::SmallString::new();
  82. write!(s, "{}", node_id).unwrap();
  83. node.dyn_ref::<Element>()
  84. .unwrap()
  85. .set_attribute("dioxus-id", s.as_str())
  86. .unwrap();
  87. self.interpreter.set_node(node_id.0, node.clone());
  88. // self.nodes[node_id.0] = Some(node.clone());
  89. *cur_place += 1;
  90. nodes.push(node.clone());
  91. place.push(0);
  92. // we cant have the last node be text
  93. let mut last_node_was_text = false;
  94. for child in vel.children {
  95. self.rehydrate_single(nodes, place, dom, child, &mut last_node_was_text)?;
  96. }
  97. for listener in vel.listeners {
  98. self.interpreter.NewEventListener(
  99. listener.event,
  100. listener.mounted_node.get().unwrap().as_u64(),
  101. self.handler.as_ref().unchecked_ref(),
  102. );
  103. }
  104. place.pop();
  105. nodes.pop();
  106. if cfg!(debug_assertions) {
  107. let el = node.dyn_ref::<Element>().unwrap();
  108. let name = el.tag_name().to_lowercase();
  109. assert_eq!(name, vel.tag);
  110. }
  111. }
  112. VNode::Placeholder(el) => {
  113. let node_id = el.id.get().ok_or(VNodeNotInitialized)?;
  114. let cur_place = place.last_mut().unwrap();
  115. let node = nodes.last().unwrap().child_nodes().get(*cur_place).unwrap();
  116. self.interpreter.set_node(node_id.0, node);
  117. // self.nodes[node_id.0] = Some(node);
  118. *cur_place += 1;
  119. }
  120. VNode::Fragment(el) => {
  121. for el in el.children {
  122. self.rehydrate_single(nodes, place, dom, el, last_node_was_text)?;
  123. }
  124. }
  125. VNode::Component(el) => {
  126. let scope = dom.get_scope(el.scope.get().unwrap()).unwrap();
  127. let node = scope.root_node();
  128. self.rehydrate_single(nodes, place, dom, node, last_node_was_text)?;
  129. }
  130. }
  131. Ok(())
  132. }
  133. }