chore: get create working and simplify dynamic nodes

This commit is contained in:
Jonathan Kelley committed 2022-11-30 11:24:13 -05:00
1 parent 16a521a601
commit 3c19def550
16 files changed
+168 -173

No files matched your search

+2 -2
View File
@@ -30,7 +30,7 @@ fn app(cx: Scope) -> Element {
} }
fn BlogPost(cx: Scope) -> Element { fn BlogPost(cx: Scope) -> Element {
let post = dioxus_router::use_route(&cx).last_segment()?; let post = dioxus_router::use_route(&cx).last_segment().unwrap();
cx.render(rsx! { cx.render(rsx! {
div { div {
@@ -46,7 +46,7 @@ struct Query {
} }
fn User(cx: Scope) -> Element { fn User(cx: Scope) -> Element {
let post = dioxus_router::use_route(&cx).last_segment()?; let post = dioxus_router::use_route(&cx).last_segment().unwrap();
let query = dioxus_router::use_route(&cx) let query = dioxus_router::use_route(&cx)
.query::<Query>() .query::<Query>()
+2 -2
View File
@@ -165,13 +165,13 @@ fn app(cx: Scope) -> Element {
// Can pass in props directly as an expression // Can pass in props directly as an expression
{ {
let props = TallerProps {a: "hello", children: Default::default()}; let props = TallerProps {a: "hello", children: cx.render(rsx!(()))};
rsx!(Taller { ..props }) rsx!(Taller { ..props })
} }
// Spreading can also be overridden manually // Spreading can also be overridden manually
Taller { Taller {
..TallerProps { a: "ballin!", children: Default::default() }, ..TallerProps { a: "ballin!", children: cx.render(rsx!(()) )},
a: "not ballin!" a: "not ballin!"
} }
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
factory::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, AttributeValue, DynamicNode, factory::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, AttributeValue, DynamicNode,
ScopeId, VFragment, ScopeId,
}; };
use bumpalo::boxed::Box as BumpBox; use bumpalo::boxed::Box as BumpBox;
@@ -101,7 +101,7 @@ impl VirtualDom {
for (idx, _) in node.template.roots.iter().enumerate() { for (idx, _) in node.template.roots.iter().enumerate() {
match node.dynamic_root(idx) { match node.dynamic_root(idx) {
Some(DynamicNode::Component(c)) => self.drop_scope(c.scope.get().unwrap()), Some(DynamicNode::Component(c)) => self.drop_scope(c.scope.get().unwrap()),
Some(DynamicNode::Fragment(VFragment::NonEmpty(nodes))) => { Some(DynamicNode::Fragment(nodes)) => {
for node in *nodes { for node in *nodes {
self.drop_scope_inner(node); self.drop_scope_inner(node);
} }
+24 -26
View File
@@ -1,11 +1,13 @@
use std::cell::Cell;
use crate::factory::RenderReturn; use crate::factory::RenderReturn;
use crate::innerlude::{VComponent, VFragment, VText}; use crate::innerlude::{VComponent, VText};
use crate::mutations::Mutation; use crate::mutations::Mutation;
use crate::mutations::Mutation::*; use crate::mutations::Mutation::*;
use crate::nodes::VNode; use crate::nodes::VNode;
use crate::nodes::{DynamicNode, TemplateNode}; use crate::nodes::{DynamicNode, TemplateNode};
use crate::virtual_dom::VirtualDom; use crate::virtual_dom::VirtualDom;
use crate::{AttributeValue, ScopeId, SuspenseContext, TemplateAttribute}; use crate::{AttributeValue, ElementId, ScopeId, SuspenseContext, TemplateAttribute};
impl<'b> VirtualDom { impl<'b> VirtualDom {
/// Create a new template [`VNode`] and write it to the [`Mutations`] buffer. /// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
@@ -55,15 +57,14 @@ impl<'b> VirtualDom {
1 1
} }
DynamicNode::Fragment(VFragment::Empty(slot)) => { DynamicNode::Placeholder(slot) => {
let id = self.next_element(template, template.template.node_paths[*id]); let id = self.next_element(template, template.template.node_paths[*id]);
slot.set(id); slot.set(id);
self.mutations.push(CreatePlaceholder { id }); self.mutations.push(CreatePlaceholder { id });
1 1
} }
DynamicNode::Fragment(VFragment::NonEmpty(_)) DynamicNode::Fragment(_) | DynamicNode::Component { .. } => {
| DynamicNode::Component { .. } => {
self.create_dynamic_node(template, &template.dynamic_nodes[*id], *id) self.create_dynamic_node(template, &template.dynamic_nodes[*id], *id)
} }
} }
@@ -309,7 +310,8 @@ impl<'b> VirtualDom {
use DynamicNode::*; use DynamicNode::*;
match node { match node {
Text(text) => self.create_dynamic_text(template, text, idx), Text(text) => self.create_dynamic_text(template, text, idx),
Fragment(frag) => self.create_fragment(frag, template, idx), Fragment(frag) => self.create_fragment(frag),
Placeholder(frag) => self.create_placeholder(frag, template, idx),
Component(component) => self.create_component_node(template, component, idx), Component(component) => self.create_component_node(template, component, idx),
} }
} }
@@ -340,34 +342,30 @@ impl<'b> VirtualDom {
0 0
} }
pub(crate) fn create_fragment( pub(crate) fn create_placeholder(
&mut self, &mut self,
frag: &'b VFragment<'b>, slot: &Cell<ElementId>,
template: &'b VNode<'b>, template: &'b VNode<'b>,
idx: usize, idx: usize,
) -> usize { ) -> usize {
match frag { // Allocate a dynamic element reference for this text node
VFragment::NonEmpty(nodes) => { let id = self.next_element(template, template.template.node_paths[idx]);
nodes.iter().fold(0, |acc, child| acc + self.create(child))
}
VFragment::Empty(slot) => { // Make sure the text node is assigned to the correct element
// Allocate a dynamic element reference for this text node slot.set(id);
let id = self.next_element(template, template.template.node_paths[idx]);
// Make sure the text node is assigned to the correct element // Assign the ID to the existing node in the template
slot.set(id); self.mutations.push(AssignId {
path: &template.template.node_paths[idx][1..],
id,
});
// Assign the ID to the existing node in the template // Since the placeholder is already in the DOM, we don't create any new nodes
self.mutations.push(AssignId { 0
path: &template.template.node_paths[idx][1..], }
id,
});
// Since the placeholder is already in the DOM, we don't create any new nodes pub(crate) fn create_fragment(&mut self, nodes: &'b [VNode<'b>]) -> usize {
0 nodes.iter().fold(0, |acc, child| acc + self.create(child))
}
}
} }
pub(super) fn create_component_node( pub(super) fn create_component_node(
+17 -54
View File
@@ -1,7 +1,7 @@
use crate::{ use crate::{
arena::ElementId, arena::ElementId,
factory::RenderReturn, factory::RenderReturn,
innerlude::{DirtyScope, VComponent, VFragment, VText}, innerlude::{DirtyScope, VComponent, VText},
mutations::Mutation, mutations::Mutation,
nodes::{DynamicNode, VNode}, nodes::{DynamicNode, VNode},
scopes::ScopeId, scopes::ScopeId,
@@ -10,7 +10,6 @@ use crate::{
}; };
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use std::cell::Cell;
use DynamicNode::*; use DynamicNode::*;
impl<'b> VirtualDom { impl<'b> VirtualDom {
@@ -101,7 +100,7 @@ impl<'b> VirtualDom {
{ {
match (left_node, right_node) { match (left_node, right_node) {
(Text(left), Text(right)) => self.diff_vtext(left, right), (Text(left), Text(right)) => self.diff_vtext(left, right),
(Fragment(left), Fragment(right)) => self.diff_vfragment(left, right), (Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right),
(Component(left), Component(right)) => { (Component(left), Component(right)) => {
self.diff_vcomponent(left, right, right_template, idx) self.diff_vcomponent(left, right, right_template, idx)
} }
@@ -231,40 +230,6 @@ impl<'b> VirtualDom {
} }
} }
fn diff_vfragment(&mut self, left: &'b VFragment<'b>, right: &'b VFragment<'b>) {
use VFragment::*;
match (left, right) {
(Empty(l), Empty(r)) => r.set(l.get()),
(Empty(l), NonEmpty(r)) => self.replace_placeholder_with_nodes(l, r),
(NonEmpty(l), Empty(r)) => self.replace_nodes_with_placeholder(l, r),
(NonEmpty(old), NonEmpty(new)) => self.diff_non_empty_fragment(new, old),
}
}
fn replace_placeholder_with_nodes(&mut self, l: &'b Cell<ElementId>, r: &'b [VNode<'b>]) {
let m = self.create_children(r);
let id = l.get();
self.mutations.push(Mutation::ReplaceWith { id, m });
self.reclaim(id);
}
fn replace_nodes_with_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b Cell<ElementId>) {
// Create the placeholder first, ensuring we get a dedicated ID for the placeholder
let placeholder = self.next_element(&l[0], &[]);
r.set(placeholder);
self.mutations
.push(Mutation::CreatePlaceholder { id: placeholder });
// Remove the old nodes, except for onea
let first = self.replace_inner(&l[0]);
self.remove_nodes(&l[1..]);
self.mutations
.push(Mutation::ReplaceWith { id: first, m: 1 });
self.try_reclaim(first);
}
/// Remove all the top-level nodes, returning the firstmost root ElementId /// Remove all the top-level nodes, returning the firstmost root ElementId
/// ///
/// All IDs will be garbage collected /// All IDs will be garbage collected
@@ -272,8 +237,8 @@ impl<'b> VirtualDom {
let id = match node.dynamic_root(0) { let id = match node.dynamic_root(0) {
None => node.root_ids[0].get(), None => node.root_ids[0].get(),
Some(Text(t)) => t.id.get(), Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::Empty(e))) => e.get(), Some(Placeholder(e)) => e.get(),
Some(Fragment(VFragment::NonEmpty(nodes))) => { Some(Fragment(nodes)) => {
let id = self.replace_inner(&nodes[0]); let id = self.replace_inner(&nodes[0]);
self.remove_nodes(&nodes[1..]); self.remove_nodes(&nodes[1..]);
id id
@@ -317,10 +282,8 @@ impl<'b> VirtualDom {
}; };
} }
Text(t) => self.reclaim(t.id.get()), Text(t) => self.reclaim(t.id.get()),
Fragment(VFragment::Empty(t)) => self.reclaim(t.get()), Placeholder(t) => self.reclaim(t.get()),
Fragment(VFragment::NonEmpty(nodes)) => { Fragment(nodes) => nodes.iter().for_each(|node| self.clean_up_node(node)),
nodes.iter().for_each(|node| self.clean_up_node(node))
}
}; };
} }
@@ -351,12 +314,12 @@ impl<'b> VirtualDom {
self.mutations.push(Mutation::Remove { id }); self.mutations.push(Mutation::Remove { id });
self.reclaim(id); self.reclaim(id);
} }
Some(Fragment(VFragment::Empty(e))) => { Some(Placeholder(e)) => {
let id = e.get(); let id = e.get();
self.mutations.push(Mutation::Remove { id }); self.mutations.push(Mutation::Remove { id });
self.reclaim(id); self.reclaim(id);
} }
Some(Fragment(VFragment::NonEmpty(nodes))) => self.remove_nodes(nodes), Some(Fragment(nodes)) => self.remove_nodes(nodes),
Some(Component(comp)) => { Some(Component(comp)) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
@@ -750,8 +713,8 @@ impl<'b> VirtualDom {
for (idx, _) in node.template.roots.iter().enumerate() { for (idx, _) in node.template.roots.iter().enumerate() {
let id = match node.dynamic_root(idx) { let id = match node.dynamic_root(idx) {
Some(Text(t)) => t.id.get(), Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::Empty(t))) => t.get(), Some(Placeholder(t)) => t.get(),
Some(Fragment(VFragment::NonEmpty(t))) => return self.remove_nodes(t), Some(Fragment(t)) => return self.remove_nodes(t),
Some(Component(comp)) => return self.remove_component(comp.scope.get().unwrap()), Some(Component(comp)) => return self.remove_component(comp.scope.get().unwrap()),
None => node.root_ids[idx].get(), None => node.root_ids[idx].get(),
}; };
@@ -793,12 +756,12 @@ impl<'b> VirtualDom {
self.mutations.push(Mutation::PushRoot { id: t.id.get() }); self.mutations.push(Mutation::PushRoot { id: t.id.get() });
onstack += 1; onstack += 1;
} }
Some(Fragment(VFragment::Empty(t))) => { Some(Placeholder(t)) => {
self.mutations.push(Mutation::PushRoot { id: t.get() }); self.mutations.push(Mutation::PushRoot { id: t.get() });
onstack += 1; onstack += 1;
} }
Some(Fragment(VFragment::NonEmpty(t))) => { Some(Fragment(nodes)) => {
for node in *t { for node in *nodes {
onstack += self.push_all_real_nodes(node); onstack += self.push_all_real_nodes(node);
} }
} }
@@ -842,8 +805,8 @@ impl<'b> VirtualDom {
match node.dynamic_root(0) { match node.dynamic_root(0) {
None => node.root_ids[0].get(), None => node.root_ids[0].get(),
Some(Text(t)) => t.id.get(), Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::NonEmpty(t))) => self.find_first_element(&t[0]), Some(Fragment(t)) => self.find_first_element(&t[0]),
Some(Fragment(VFragment::Empty(t))) => t.get(), Some(Placeholder(t)) => t.get(),
Some(Component(comp)) => { Some(Component(comp)) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
@@ -858,8 +821,8 @@ impl<'b> VirtualDom {
match node.dynamic_root(node.template.roots.len() - 1) { match node.dynamic_root(node.template.roots.len() - 1) {
None => node.root_ids.last().unwrap().get(), None => node.root_ids.last().unwrap().get(),
Some(Text(t)) => t.id.get(), Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::NonEmpty(t))) => self.find_last_element(t.last().unwrap()), Some(Fragment(t)) => self.find_last_element(t.last().unwrap()),
Some(Fragment(VFragment::Empty(t))) => t.get(), Some(Placeholder(t)) => t.get(),
Some(Component(comp)) => { Some(Component(comp)) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } { match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
+18 -10
View File
@@ -10,7 +10,7 @@ use std::future::Future;
use crate::{ use crate::{
any_props::{AnyProps, VProps}, any_props::{AnyProps, VProps},
arena::ElementId, arena::ElementId,
innerlude::{DynamicNode, EventHandler, VComponent, VFragment, VText}, innerlude::{DynamicNode, EventHandler, VComponent, VText},
Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode, Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode,
}; };
@@ -148,12 +148,20 @@ pub trait IntoDynNode<'a, A = ()> {
impl<'a> IntoDynNode<'a> for () { impl<'a> IntoDynNode<'a> for () {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))) DynamicNode::placeholder()
} }
} }
impl<'a> IntoDynNode<'a> for VNode<'a> { impl<'a> IntoDynNode<'a> for VNode<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(_cx.bump().alloc([self]))) DynamicNode::Fragment(_cx.bump().alloc([self]))
}
}
impl<'a> IntoDynNode<'a> for Element<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self {
Ok(val) => val.into_vnode(_cx),
_ => DynamicNode::placeholder(),
}
} }
} }
@@ -161,7 +169,7 @@ impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self { match self {
Some(val) => val.into_vnode(_cx), Some(val) => val.into_vnode(_cx),
None => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))), None => DynamicNode::placeholder(),
} }
} }
} }
@@ -170,14 +178,14 @@ impl<'a> IntoDynNode<'a> for &Element<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self.as_ref() { match self.as_ref() {
Ok(val) => val.clone().into_vnode(_cx), Ok(val) => val.clone().into_vnode(_cx),
_ => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))), _ => DynamicNode::placeholder(),
} }
} }
} }
impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> { impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(cx.bump().alloc([self.call(cx)]))) DynamicNode::Fragment(cx.bump().alloc([self.call(cx)]))
} }
} }
@@ -201,14 +209,14 @@ impl<'b> IntoDynNode<'b> for Arguments<'_> {
impl<'a> IntoDynNode<'a> for &'a VNode<'a> { impl<'a> IntoDynNode<'a> for &'a VNode<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(_cx.bump().alloc([VNode { DynamicNode::Fragment(_cx.bump().alloc([VNode {
parent: self.parent, parent: self.parent,
template: self.template, template: self.template,
root_ids: self.root_ids, root_ids: self.root_ids,
key: self.key, key: self.key,
dynamic_nodes: self.dynamic_nodes, dynamic_nodes: self.dynamic_nodes,
dynamic_attrs: self.dynamic_attrs, dynamic_attrs: self.dynamic_attrs,
}]))) }]))
} }
} }
@@ -243,8 +251,8 @@ where
let children = nodes.into_bump_slice(); let children = nodes.into_bump_slice();
match children.len() { match children.len() {
0 => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))), 0 => DynamicNode::placeholder(),
_ => DynamicNode::Fragment(VFragment::NonEmpty(children)), _ => DynamicNode::Fragment(children),
} }
} }
} }
+2 -1
View File
@@ -24,6 +24,7 @@ pub(crate) mod innerlude {
pub use crate::dirty_scope::*; pub use crate::dirty_scope::*;
pub use crate::error_boundary::*; pub use crate::error_boundary::*;
pub use crate::events::*; pub use crate::events::*;
pub use crate::factory::RenderReturn;
pub use crate::fragment::*; pub use crate::fragment::*;
pub use crate::lazynodes::*; pub use crate::lazynodes::*;
pub use crate::mutations::*; pub use crate::mutations::*;
@@ -87,6 +88,7 @@ pub use crate::innerlude::{
Mutations, Mutations,
NodeFactory, NodeFactory,
Properties, Properties,
RenderReturn,
Scope, Scope,
ScopeId, ScopeId,
ScopeState, ScopeState,
@@ -99,7 +101,6 @@ pub use crate::innerlude::{
TemplateNode, TemplateNode,
UiEvent, UiEvent,
VComponent, VComponent,
VFragment,
VNode, VNode,
VText, VText,
VirtualDom, VirtualDom,
-4
View File
@@ -150,10 +150,6 @@ pub enum Mutation<'a> {
id: ElementId, id: ElementId,
}, },
SetInnerText {
value: &'a str,
},
SetText { SetText {
value: &'a str, value: &'a str,
id: ElementId, id: ElementId,
+5 -7
View File
@@ -89,13 +89,17 @@ pub enum TemplateNode<'a> {
pub enum DynamicNode<'a> { pub enum DynamicNode<'a> {
Component(VComponent<'a>), Component(VComponent<'a>),
Text(VText<'a>), Text(VText<'a>),
Fragment(VFragment<'a>), Placeholder(Cell<ElementId>),
Fragment(&'a [VNode<'a>]),
} }
impl<'a> DynamicNode<'a> { impl<'a> DynamicNode<'a> {
pub fn is_component(&self) -> bool { pub fn is_component(&self) -> bool {
matches!(self, DynamicNode::Component(_)) matches!(self, DynamicNode::Component(_))
} }
pub fn placeholder() -> Self {
Self::Placeholder(Cell::new(ElementId(0)))
}
} }
pub struct VComponent<'a> { pub struct VComponent<'a> {
@@ -122,12 +126,6 @@ pub struct VText<'a> {
pub value: &'a str, pub value: &'a str,
} }
#[derive(Debug)]
pub enum VFragment<'a> {
Empty(Cell<ElementId>),
NonEmpty(&'a [VNode<'a>]),
}
#[derive(Debug)] #[derive(Debug)]
pub enum TemplateAttribute<'a> { pub enum TemplateAttribute<'a> {
Static { Static {
+2 -2
View File
@@ -7,7 +7,7 @@ use crate::{
scheduler::RcWake, scheduler::RcWake,
scopes::{ScopeId, ScopeState}, scopes::{ScopeId, ScopeState},
virtual_dom::VirtualDom, virtual_dom::VirtualDom,
AttributeValue, DynamicNode, VFragment, VNode, AttributeValue, DynamicNode, VNode,
}; };
use futures_util::FutureExt; use futures_util::FutureExt;
use std::{ use std::{
@@ -75,7 +75,7 @@ impl VirtualDom {
c.props.set(None); c.props.set(None);
} }
} }
DynamicNode::Fragment(VFragment::NonEmpty(f)) => { DynamicNode::Fragment(f) => {
for node in *f { for node in *f {
self.ensure_drop_safety_inner(node); self.ensure_drop_safety_inner(node);
} }
+1 -1
View File
@@ -67,7 +67,7 @@ impl DesktopController {
let name = value.event.clone(); let name = value.event.clone();
let el_id = ElementId(value.mounted_dom_id); let el_id = ElementId(value.mounted_dom_id);
if let Some(evt) = decode_event(value) { if let Some(evt) = decode_event(value) {
dom.handle_event(&name, evt, el_id, true, EventPriority::Medium); dom.handle_event(&name, evt, el_id, true);
} }
} }
} }
+49 -26
View File
@@ -132,16 +132,13 @@ export class Interpreter {
this.nodes[root] = node; this.nodes[root] = node;
this.stack.push(node); this.stack.push(node);
} }
CreateElement(tag, root) { CreateElement(tag) {
const el = document.createElement(tag); const el = document.createElement(tag);
this.nodes[root] = el;
this.stack.push(el); this.stack.push(el);
} }
CreateElementNs(tag, root, ns) { CreateElementNs(tag, ns) {
console.log("creating element", tag, root, ns);
let el = document.createElementNS(ns, tag); let el = document.createElementNS(ns, tag);
this.stack.push(el); this.stack.push(el);
this.nodes[root] = el;
} }
CreatePlaceholder(root) { CreatePlaceholder(root) {
let el = document.createElement("pre"); let el = document.createElement("pre");
@@ -149,6 +146,11 @@ export class Interpreter {
this.stack.push(el); this.stack.push(el);
this.nodes[root] = el; this.nodes[root] = el;
} }
CreateStaticPlaceholder() {
let el = document.createElement("pre");
el.hidden = true;
this.stack.push(el);
}
NewEventListener(event_name, root, handler, bubbles) { NewEventListener(event_name, root, handler, bubbles) {
const element = this.nodes[root]; const element = this.nodes[root];
element.setAttribute("data-dioxus-id", `${root}`); element.setAttribute("data-dioxus-id", `${root}`);
@@ -162,9 +164,16 @@ export class Interpreter {
SetText(root, text) { SetText(root, text) {
this.nodes[root].textContent = text; this.nodes[root].textContent = text;
} }
SetAttribute(root, field, value, ns) { SetAttribute(id, field, value, ns) {
const node = this.nodes[id];
this.SetAttributeInner(node, field, value, ns);
}
SetStaticAttribute(field, value, ns) {
const node = this.top();
this.SetAttributeInner(node, field, value, ns);
}
SetAttributeInner(node, field, value, ns) {
const name = field; const name = field;
const node = this.nodes[root];
if (ns === "style") { if (ns === "style") {
// ????? why do we need to do this // ????? why do we need to do this
if (node.style === undefined) { if (node.style === undefined) {
@@ -248,9 +257,9 @@ export class Interpreter {
let node = this.LoadChild(path); let node = this.LoadChild(path);
node.replaceWith(...els); node.replaceWith(...els);
} }
LoadTemplate(name, index) { LoadTemplate(name, index, id) {
console.log("loading template", name, index);
let node = this.templates[name][index].cloneNode(true); let node = this.templates[name][index].cloneNode(true);
this.nodes[id] = node;
this.stack.push(node); this.stack.push(node);
} }
SaveTemplate(name, m) { SaveTemplate(name, m) {
@@ -265,24 +274,38 @@ export class Interpreter {
this.AssignId(edit.path, edit.id); this.AssignId(edit.path, edit.id);
break; break;
case "CreateElement": case "CreateElement":
if (edit.namespace !== null && edit.namespace !== undefined) { this.CreateElement(edit.name);
this.CreateElementNs(edit.name, edit.id, edit.namespace); break;
} else { case "CreateElementNs":
this.CreateElement(edit.name, edit.id); this.CreateElementNs(edit.name, edit.namespace);
}
break; break;
case "CreatePlaceholder": case "CreatePlaceholder":
this.CreatePlaceholder(edit.id); this.CreatePlaceholder(edit.id);
break; break;
case "CreateTextNode": case "CreateStaticText":
this.CreateTextNode(edit.value); this.CreateTextNode(edit.value);
break; break;
case "CreateStaticPlaceholder":
this.CreateStaticPlaceholder();
break;
case "CreateTextPlaceholder":
this.CreateRawText("placeholder");
break;
case "CreateStaticText": case "CreateStaticText":
this.CreateRawText(edit.value);
break;
case "CreateTextNode":
this.CreateTextNode(edit.value); this.CreateTextNode(edit.value);
break; break;
case "HydrateText": case "HydrateText":
this.HydrateText(edit.path, edit.value, edit.id); this.HydrateText(edit.path, edit.value, edit.id);
break; break;
case "LoadTemplate":
this.LoadTemplate(edit.name, edit.index);
break;
case "SaveTemplate":
this.SaveTemplate(edit.name, edit.m);
break;
case "PushRoot": case "PushRoot":
this.PushRoot(edit.id); this.PushRoot(edit.id);
break; break;
@@ -293,29 +316,29 @@ export class Interpreter {
this.ReplacePlaceholder(edit.path, edit.m); this.ReplacePlaceholder(edit.path, edit.m);
break; break;
case "InsertAfter": case "InsertAfter":
this.InsertAfter(edit.id, edit.n); this.InsertAfter(edit.id, edit.m);
break; break;
case "InsertBefore": case "InsertBefore":
this.InsertBefore(edit.id, edit.n); this.InsertBefore(edit.id, edit.m);
break; break;
case "Remove": case "Remove":
this.Remove(edit.id); this.Remove(edit.id);
break; break;
case "LoadTemplate":
this.LoadTemplate(edit.name, edit.index);
break;
case "SaveTemplate":
this.SaveTemplate(edit.name, edit.m);
break;
case "CreateElementNs":
this.CreateElementNs(edit.name, edit.id, edit.ns);
break;
case "SetText": case "SetText":
this.SetText(edit.id, edit.value); this.SetText(edit.id, edit.value);
break; break;
case "SetAttribute": case "SetAttribute":
this.SetAttribute(edit.id, edit.name, edit.value, edit.ns); this.SetAttribute(edit.id, edit.name, edit.value, edit.ns);
break; break;
case "SetStaticAttribute":
this.SetStaticAttribute(edit.name, edit.value, edit.ns);
break;
case "SetBoolAttribute":
this.SetAttribute(edit.id, edit.name, edit.value, edit.ns);
break;
case "SetInnerText":
console.log("Set inner text?");
break;
case "RemoveAttribute": case "RemoveAttribute":
this.RemoveAttribute(edit.id, edit.name, edit.ns); this.RemoveAttribute(edit.id, edit.name, edit.ns);
break; break;
+1 -1
View File
@@ -47,5 +47,5 @@ pub fn Redirect<'a>(cx: Scope<'a, RedirectProps<'a>>) -> Element {
router.replace_route(cx.props.to, None, None); router.replace_route(cx.props.to, None, None);
} }
None cx.render(rsx!(()))
} }
+3 -2
View File
@@ -29,7 +29,8 @@ pub struct RouteProps<'a> {
pub fn Route<'a>(cx: Scope<'a, RouteProps<'a>>) -> Element { pub fn Route<'a>(cx: Scope<'a, RouteProps<'a>>) -> Element {
let router_root = cx let router_root = cx
.use_hook(|| cx.consume_context::<Arc<RouterCore>>()) .use_hook(|| cx.consume_context::<Arc<RouterCore>>())
.as_ref()?; .as_ref()
.unwrap();
cx.use_hook(|| { cx.use_hook(|| {
// create a bigger, better, longer route if one above us exists // create a bigger, better, longer route if one above us exists
@@ -55,6 +56,6 @@ pub fn Route<'a>(cx: Scope<'a, RouteProps<'a>>) -> Element {
cx.render(rsx!(&cx.props.children)) cx.render(rsx!(&cx.props.children))
} else { } else {
log::trace!("Route should *not* render: {:?}", cx.scope_id()); log::trace!("Route should *not* render: {:?}", cx.scope_id());
None cx.render(rsx!(()))
} }
} }
+2
View File
@@ -3,6 +3,7 @@ use std::fmt::Write;
pub struct StringCache { pub struct StringCache {
pub segments: Vec<Segment>, pub segments: Vec<Segment>,
pub template: Template<'static>,
} }
#[derive(Default)] #[derive(Default)]
@@ -40,6 +41,7 @@ impl StringCache {
Ok(Self { Ok(Self {
segments: chain.segments, segments: chain.segments,
template: template.template,
}) })
} }
+38 -33
View File
@@ -1,5 +1,5 @@
use super::cache::Segment; use super::cache::Segment;
use dioxus_core::{prelude::*, AttributeValue, DynamicNode, VText}; use dioxus_core::{prelude::*, AttributeValue, DynamicNode, RenderReturn, VText};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Write; use std::fmt::Write;
use std::rc::Rc; use std::rc::Rc;
@@ -9,7 +9,7 @@ use crate::cache::StringCache;
/// A virtualdom renderer that caches the templates it has seen for faster rendering /// A virtualdom renderer that caches the templates it has seen for faster rendering
#[derive(Default)] #[derive(Default)]
pub struct SsrRender { pub struct SsrRender {
template_cache: HashMap<Template<'static>, Rc<StringCache>>, template_cache: HashMap<&'static str, Rc<StringCache>>,
} }
impl SsrRender { impl SsrRender {
@@ -18,7 +18,11 @@ impl SsrRender {
let root = scope.root_node(); let root = scope.root_node();
let mut out = String::new(); let mut out = String::new();
// self.render_template(&mut out, dom, root).unwrap();
match root {
RenderReturn::Sync(Ok(node)) => self.render_template(&mut out, dom, node).unwrap(),
_ => {}
};
out out
} }
@@ -31,7 +35,7 @@ impl SsrRender {
) -> std::fmt::Result { ) -> std::fmt::Result {
let entry = self let entry = self
.template_cache .template_cache
.entry(template.template) .entry(template.template.id)
.or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap())) .or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap()))
.clone(); .clone();
@@ -46,37 +50,38 @@ impl SsrRender {
}; };
} }
Segment::Node(idx) => match &template.dynamic_nodes[*idx] { Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
DynamicNode::Component(_) => todo!(), DynamicNode::Component(node) => {
DynamicNode::Text(_) => todo!(), let id = node.scope.get().unwrap();
DynamicNode::Fragment(_) => todo!(), let scope = dom.get_scope(id).unwrap();
DynamicNode::Placeholder(_) => todo!(), let node = scope.root_node();
// todo!() match node {
// DynamicNode::Text(VText { id, value }) => { RenderReturn::Sync(Ok(node)) => self.render_template(buf, dom, node)?,
// // in SSR, we are concerned that we can't hunt down the right text node since they might get merged _ => todo!(),
// // if !*inner { }
// write!(buf, "<!--#-->")?; }
// // } DynamicNode::Text(text) => {
// in SSR, we are concerned that we can't hunt down the right text node since they might get merged
// if !*inner {
// write!(buf, "<!--#-->")?;
// }
// // todo: escape the text // todo: escape the text
// write!(buf, "{}", value)?; write!(buf, "{}", text.value)?;
// // if !*inner { // if !*inner {
// write!(buf, "<!--/#-->")?; // write!(buf, "<!--/#-->")?;
// // } // }
// } }
// DynamicNode::Fragment { nodes, .. } => { DynamicNode::Fragment(nodes) => {
// for child in *nodes { for child in *nodes {
// self.render_template(buf, dom, child)?; self.render_template(buf, dom, child)?;
// } }
// } }
// DynamicNode::Component { scope, .. } => {
// let id = scope.get().unwrap(); DynamicNode::Placeholder(_el) => {
// let scope = dom.get_scope(id).unwrap(); // todo write a placeholder if in pre-render mode
// self.render_template(buf, dom, scope.root_node())?; // write!(buf, "<!--placeholder-->")?;
// } }
// DynamicNode::Placeholder(_el) => {
// write!(buf, "<!--placeholder-->")?;
// }
}, },
Segment::PreRendered(contents) => buf.push_str(contents), Segment::PreRendered(contents) => buf.push_str(contents),