Pārlūkot izejas kodu

feat: get desktop working with new template strategy

Jonathan Kelley 2 gadi atpakaļ
vecāks
revīzija
7b1cdb7d85

+ 3 - 3
packages/core/src/create.rs

@@ -40,7 +40,7 @@ impl<'b> VirtualDom {
         for (root_idx, root) in template.template.roots.iter().enumerate() {
             // We might need to generate an ID for the root node
             on_stack += match root {
-                TemplateNode::DynamicText(id) | TemplateNode::Dynamic(id) => {
+                TemplateNode::DynamicText { id } | TemplateNode::Dynamic { id } => {
                     match &template.dynamic_nodes[*id] {
                         // a dynamic text node doesn't replace a template node, instead we create it on the fly
                         DynamicNode::Text(VText { id: slot, value }) => {
@@ -70,7 +70,7 @@ impl<'b> VirtualDom {
                     }
                 }
 
-                TemplateNode::Element { .. } | TemplateNode::Text(_) => {
+                TemplateNode::Element { .. } | TemplateNode::Text { .. } => {
                     let this_id = self.next_root(template, root_idx);
 
                     template.root_ids[root_idx].set(this_id);
@@ -215,7 +215,7 @@ impl<'b> VirtualDom {
             .filter(|root| {
                 matches!(
                     root,
-                    TemplateNode::Dynamic(_) | TemplateNode::DynamicText(_)
+                    TemplateNode::Dynamic { .. } | TemplateNode::DynamicText { .. }
                 )
             })
             .count();

+ 1 - 1
packages/core/src/diff.rs

@@ -911,7 +911,7 @@ fn matching_components<'a>(
         .zip(right.template.roots.iter())
         .map(|(l, r)| {
             let (l, r) = match (l, r) {
-                (TemplateNode::Dynamic(l), TemplateNode::Dynamic(r)) => (l, r),
+                (TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r),
                 _ => return None,
             };
 

+ 1 - 0
packages/core/src/mutations.rs

@@ -13,6 +13,7 @@ use crate::{arena::ElementId, ScopeId, Template};
 /// Templates, however, apply to all subtrees, not just target subtree.
 ///
 /// Mutations are the only link between the RealDOM and the VirtualDOM.
+#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
 #[derive(Debug, Default)]
 #[must_use = "not handling edits can lead to visual inconsistencies in UI"]
 pub struct Mutations<'a> {

+ 11 - 7
packages/core/src/nodes.rs

@@ -78,8 +78,8 @@ impl<'a> VNode<'a> {
     /// Returns [`None`] if the root is actually a static node (Element/Text)
     pub fn dynamic_root(&self, idx: usize) -> Option<&'a DynamicNode<'a>> {
         match &self.template.roots[idx] {
-            TemplateNode::Element { .. } | TemplateNode::Text(_) => None,
-            TemplateNode::Dynamic(id) | TemplateNode::DynamicText(id) => {
+            TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None,
+            TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
                 Some(&self.dynamic_nodes[*id])
             }
         }
@@ -132,7 +132,7 @@ pub struct Template<'a> {
 ///
 /// This can be created at compile time, saving the VirtualDom time when diffing the tree
 #[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
+#[cfg_attr(feature = "serialize", derive(serde::Serialize), serde(tag = "type"))]
 pub enum TemplateNode<'a> {
     /// An statically known element in the dom.
     ///
@@ -159,15 +159,15 @@ pub enum TemplateNode<'a> {
     },
 
     /// This template node is just a piece of static text
-    Text(&'a str),
+    Text { text: &'a str },
 
     /// This template node is unknown, and needs to be created at runtime.
-    Dynamic(usize),
+    Dynamic { id: usize },
 
     /// This template node is known to be some text, but needs to be created at runtime
     ///
     /// This is separate from the pure Dynamic variant for various optimizations
-    DynamicText(usize),
+    DynamicText { id: usize },
 }
 
 /// A node created at runtime
@@ -252,7 +252,11 @@ pub struct VText<'a> {
 
 /// An attribute of the TemplateNode, created at compile time
 #[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(
+    feature = "serialize",
+    derive(serde::Serialize, serde::Deserialize),
+    serde(tag = "type")
+)]
 pub enum TemplateAttribute<'a> {
     /// This attribute is entirely known at compile time, enabling
     Static {

+ 1 - 4
packages/desktop/src/controller.rs

@@ -54,8 +54,7 @@ impl DesktopController {
                 {
                     let edits = dom.rebuild();
                     let mut queue = edit_queue.lock().unwrap();
-                    queue.push(serde_json::to_string(&edits.templates).unwrap());
-                    queue.push(serde_json::to_string(&edits.edits).unwrap());
+                    queue.push(serde_json::to_string(&edits).unwrap());
                     proxy.send_event(UserWindowEvent::EditsReady).unwrap();
                 }
 
@@ -116,8 +115,6 @@ impl DesktopController {
 
             let (_id, view) = self.webviews.iter_mut().next().unwrap();
 
-            println!("processing pending edits {:?}", new_queue.len());
-
             for edit in new_queue.drain(..) {
                 view.evaluate_script(&format!("window.interpreter.handleEdits({})", edit))
                     .unwrap();

+ 0 - 1
packages/desktop/src/events.rs

@@ -1,6 +1,5 @@
 //! Convert a serialized event to an event trigger
 
-use dioxus_core::ElementId;
 use dioxus_html::events::*;
 use serde::{Deserialize, Serialize};
 use serde_json::from_value;

+ 3 - 3
packages/html/src/render_template.rs

@@ -33,9 +33,9 @@ fn render_template_node(node: &TemplateNode, out: &mut String) -> std::fmt::Resu
             }
             write!(out, "</{tag}>")?;
         }
-        TemplateNode::Text(t) => write!(out, "{t}")?,
-        TemplateNode::Dynamic(_) => write!(out, "<pre hidden />")?,
-        TemplateNode::DynamicText(t) => write!(out, "<!-- --> {t} <!-- -->")?,
+        TemplateNode::Text { text: t } => write!(out, "{t}")?,
+        TemplateNode::Dynamic { id: _ } => write!(out, "<pre hidden />")?,
+        TemplateNode::DynamicText { id: t } => write!(out, "<!-- --> {t} <!-- -->")?,
     };
     Ok(())
 }

+ 48 - 4
packages/interpreter/src/interpreter.js

@@ -76,9 +76,6 @@ export class Interpreter {
   pop() {
     return this.stack.pop();
   }
-  SaveTemplate(nodes, name) {
-    this.templates[name] = nodes;
-  }
   MountToRoot() {
     this.AppendChildren(this.stack.length - 1);
   }
@@ -213,10 +210,57 @@ export class Interpreter {
     }
   }
   handleEdits(edits) {
-    for (let edit of edits) {
+    // a json blob of things
+    for (let template of edits.templates) {
+      this.SaveTemplate(template);
+    }
+
+    for (let edit of edits.edits) {
       this.handleEdit(edit);
     }
   }
+  SaveTemplate(template) {
+    console.log("saving template", template);
+    let roots = [];
+    for (let root of template.roots) {
+      roots.push(this.MakeTemplateNode(root));
+    }
+    console.log("saving template", template.name, roots);
+    this.templates[template.name] = roots;
+  }
+  MakeTemplateNode(node) {
+    console.log("making template node", node);
+    switch (node.type) {
+      case "Text":
+        return document.createTextNode(node.text);
+      case "Dynamic":
+        let dyn = document.createElement("pre");
+        dyn.hidden = true;
+        return dyn;
+      case "DynamicText":
+        return document.createTextNode("placeholder");
+      case "Element":
+        let el;
+
+        if (node.namespace != null) {
+          el = document.createElementNS(node.namespace, node.tag);
+        } else {
+          el = document.createElement(node.tag);
+        }
+
+        for (let attr of node.attrs) {
+          if (attr.type == "Static") {
+            this.SetAttributeInner(el, attr.name, attr.value, attr.namespace);
+          }
+        }
+
+        for (let child of node.children) {
+          el.appendChild(this.MakeTemplateNode(child));
+        }
+
+        return el;
+    }
+  }
   AssignId(path, id) {
     this.nodes[id] = this.LoadChild(path);
   }

+ 5 - 3
packages/rsx/src/lib.rs

@@ -245,7 +245,7 @@ impl<'a> DynamicContext<'a> {
 
             BodyNode::Text(text) if text.is_static() => {
                 let text = text.source.as_ref().unwrap();
-                quote! { ::dioxus::core::TemplateNode::Text(#text) }
+                quote! { ::dioxus::core::TemplateNode::Text{ text: #text } }
             }
 
             BodyNode::RawExpr(_)
@@ -258,8 +258,10 @@ impl<'a> DynamicContext<'a> {
                 self.node_paths.push(self.current_path.clone());
 
                 match root {
-                    BodyNode::Text(_) => quote! { ::dioxus::core::TemplateNode::DynamicText(#ct) },
-                    _ => quote! { ::dioxus::core::TemplateNode::Dynamic(#ct) },
+                    BodyNode::Text(_) => {
+                        quote! { ::dioxus::core::TemplateNode::DynamicText { id: #ct } }
+                    }
+                    _ => quote! { ::dioxus::core::TemplateNode::Dynamic { id: #ct } },
                 }
             }
         }

+ 2 - 2
packages/ssr/src/cache.rs

@@ -81,8 +81,8 @@ impl StringCache {
                 }
                 cur_path.pop();
             }
-            TemplateNode::Text(text) => write!(chain, "{}", text)?,
-            TemplateNode::Dynamic(idx) | TemplateNode::DynamicText(idx) => {
+            TemplateNode::Text { text } => write!(chain, "{}", text)?,
+            TemplateNode::Dynamic { id: idx } | TemplateNode::DynamicText { id: idx } => {
                 chain.segments.push(Segment::Node(*idx))
             }
         }

+ 4 - 3
packages/web/src/dom.rs

@@ -101,9 +101,9 @@ impl WebsysDom {
                 }
                 el.dyn_into().unwrap()
             }
-            Text(t) => self.document.create_text_node(t).dyn_into().unwrap(),
-            DynamicText(_) => self.document.create_text_node("p").dyn_into().unwrap(),
-            Dynamic(_) => {
+            Text { text: t } => self.document.create_text_node(t).dyn_into().unwrap(),
+            DynamicText { id: _ } => self.document.create_text_node("p").dyn_into().unwrap(),
+            Dynamic { id: _ } => {
                 let el = self.document.create_element("pre").unwrap();
                 el.toggle_attribute("hidden");
                 el.dyn_into().unwrap()
@@ -116,6 +116,7 @@ impl WebsysDom {
         let i = &self.interpreter;
         for edit in edits.drain(..) {
             match edit {
+                AppendChildren { id, m } => i.AppendChildren(id, m),
                 AssignId { path, id } => i.AssignId(path, id.0 as u32),
                 CreatePlaceholder { id } => i.CreatePlaceholder(id.0 as u32),
                 CreateTextNode { value, id } => i.CreateTextNode(value.into(), id.0 as u32),