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:
Demonthos authored and GitHub committed 2022-09-30 12:03:06 -07:00
1 parent b32fd2d2cd
commit 047ed1e553
80 files changed
+6774 -2552

No files matched your search

+41 -2
View File
@@ -7,7 +7,7 @@
//! - tests to ensure dyn_into works for various event types.
//! - Partial delegation?>
use dioxus_core::{DomEdit, ElementId, SchedulerMsg, UserEvent};
use dioxus_core::{DomEdit, SchedulerMsg, UserEvent};
use dioxus_html::event_bubbles;
use dioxus_interpreter_js::Interpreter;
use js_sys::Function;
@@ -43,7 +43,7 @@ impl WebsysDom {
break Ok(UserEvent {
name: event_name_from_typ(&typ),
data: virtual_event_from_websys_event(event.clone(), target.clone()),
element: Some(ElementId(id)),
element: Some(id),
scope_id: None,
priority: dioxus_core::EventPriority::Medium,
bubbles: event.bubbles(),
@@ -157,6 +157,45 @@ impl WebsysDom {
let value = serde_wasm_bindgen::to_value(&value).unwrap();
self.interpreter.SetAttribute(root, field, value, ns)
}
DomEdit::CreateTemplateRef { id, template_id } => {
self.interpreter.CreateTemplateRef(id, template_id)
}
DomEdit::CreateTemplate { id } => self.interpreter.CreateTemplate(id),
DomEdit::FinishTemplate { len } => self.interpreter.FinishTemplate(len),
DomEdit::EnterTemplateRef { root } => self.interpreter.EnterTemplateRef(root),
DomEdit::ExitTemplateRef {} => self.interpreter.ExitTemplateRef(),
DomEdit::CreateTextNodeTemplate {
root,
text,
locally_static,
} => self
.interpreter
.CreateTextNodeTemplate(text, root, locally_static),
DomEdit::CreateElementTemplate {
root,
tag,
locally_static,
fully_static,
} => {
self.interpreter
.CreateElementTemplate(tag, root, locally_static, fully_static)
}
DomEdit::CreateElementNsTemplate {
root,
tag,
ns,
locally_static,
fully_static,
} => self.interpreter.CreateElementNsTemplate(
tag,
root,
ns,
locally_static,
fully_static,
),
DomEdit::CreatePlaceholderTemplate { root } => {
self.interpreter.CreatePlaceholderTemplate(root)
}
}
}
}