Subtree memorization / reactive templates (#488)
This commit adds subtree memoization to Dioxus. Subtree memoization is basically a compile-time step that drastically reduces the amount of work the diffing engine needs to do at runtime by extracting non-changing nodes out into a static "template." Templates are then understood by the various renderers in the ecosystem as a faster way of rendering the same items. For example, in the web, templates are simply a set of DOM Nodes created once and then cloned later. This is the same pattern frameworks like Lithtml and SolidJS use to achieve near-perfect performance. Subtree memoization adds an additional level of complexity to Dioxus. The RSX macro needs to be much smarter to identify changing/nonchanging nodes and generate a mapping between the Template and its runtime counterparts. This commit represents a working starter point for this work, adding support for templates for the web, desktop, liveview, ssr, and native-core renderers. In the future we will try to shrink code generation, generally improve performance, and simplify our implementation.
This commit is contained in:
1 parent
b32fd2d2cd
commit
047ed1e553
80 files changed
+6774
-2552
No files matched your search
@@ -1,6 +1,5 @@
|
||||
use crate::{GlobalAttributes, SvgAttributes};
|
||||
use dioxus_core::*;
|
||||
use std::fmt::Arguments;
|
||||
|
||||
macro_rules! builder_constructors {
|
||||
(
|
||||
@@ -28,10 +27,12 @@ macro_rules! builder_constructors {
|
||||
|
||||
impl $name {
|
||||
$(
|
||||
$(#[$attr_method])*
|
||||
pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr(stringify!($fil), val, None, false)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $fil: AttributeDiscription = AttributeDiscription{
|
||||
name: stringify!($fil),
|
||||
namespace: None,
|
||||
volatile: false
|
||||
};
|
||||
)*
|
||||
}
|
||||
)*
|
||||
@@ -57,9 +58,13 @@ macro_rules! builder_constructors {
|
||||
|
||||
impl $name {
|
||||
$(
|
||||
pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr(stringify!($fil), val, Some(stringify!($namespace)), false)
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $fil: AttributeDiscription = AttributeDiscription{
|
||||
name: stringify!($fil),
|
||||
namespace: Some(stringify!($namespace)),
|
||||
volatile: false
|
||||
};
|
||||
)*
|
||||
}
|
||||
)*
|
||||
@@ -1061,13 +1066,19 @@ impl input {
|
||||
/// - `time`
|
||||
/// - `url`
|
||||
/// - `week`
|
||||
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("type", val, None, false)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const r#type: AttributeDiscription = AttributeDiscription {
|
||||
name: "type",
|
||||
namespace: None,
|
||||
volatile: false,
|
||||
};
|
||||
|
||||
pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("value", val, None, true)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const value: AttributeDiscription = AttributeDiscription {
|
||||
name: "value",
|
||||
namespace: None,
|
||||
volatile: true,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1077,41 +1088,63 @@ volatile attributes
|
||||
impl script {
|
||||
// r#async: Bool,
|
||||
// r#type: String, // TODO could be an enum
|
||||
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("type", val, None, false)
|
||||
}
|
||||
pub fn r#script<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("script", val, None, false)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const r#type: AttributeDiscription = AttributeDiscription {
|
||||
name: "type",
|
||||
namespace: None,
|
||||
volatile: false,
|
||||
};
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const r#script: AttributeDiscription = AttributeDiscription {
|
||||
name: "script",
|
||||
namespace: None,
|
||||
volatile: false,
|
||||
};
|
||||
}
|
||||
|
||||
impl button {
|
||||
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("type", val, None, false)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const r#type: AttributeDiscription = AttributeDiscription {
|
||||
name: "type",
|
||||
namespace: None,
|
||||
volatile: false,
|
||||
};
|
||||
}
|
||||
|
||||
impl select {
|
||||
pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("value", val, None, true)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const value: AttributeDiscription = AttributeDiscription {
|
||||
name: "value",
|
||||
namespace: None,
|
||||
volatile: true,
|
||||
};
|
||||
}
|
||||
|
||||
impl option {
|
||||
pub fn selected<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("selected", val, None, true)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const selected: AttributeDiscription = AttributeDiscription {
|
||||
name: "selected",
|
||||
namespace: None,
|
||||
volatile: true,
|
||||
};
|
||||
}
|
||||
|
||||
impl textarea {
|
||||
pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("value", val, None, true)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const value: AttributeDiscription = AttributeDiscription {
|
||||
name: "value",
|
||||
namespace: None,
|
||||
volatile: true,
|
||||
};
|
||||
}
|
||||
impl label {
|
||||
pub fn r#for<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||
cx.attr("for", val, None, false)
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const r#for: AttributeDiscription = AttributeDiscription {
|
||||
name: "for",
|
||||
namespace: None,
|
||||
volatile: false,
|
||||
};
|
||||
}
|
||||
|
||||
builder_constructors! {
|
||||
|
||||
Reference in new issue
Block a user