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
@@ -34,40 +34,21 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn rsx(s: TokenStream) -> TokenStream {
|
||||
#[cfg(feature = "hot-reload")]
|
||||
let rsx_text = s.to_string();
|
||||
match syn::parse::<rsx::CallBody>(s) {
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
Ok(body) => body.to_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of the rsx! macro that does not use templates. Used for testing diffing
|
||||
#[proc_macro]
|
||||
pub fn rsx_without_templates(s: TokenStream) -> TokenStream {
|
||||
match syn::parse::<rsx::CallBody>(s) {
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
Ok(body) => {
|
||||
#[cfg(feature = "hot-reload")]
|
||||
{
|
||||
use dioxus_rsx_interpreter::captuered_context::CapturedContextBuilder;
|
||||
|
||||
match CapturedContextBuilder::from_call_body(body) {
|
||||
Ok(captured) => {
|
||||
let lazy = quote::quote! {
|
||||
LazyNodes::new(move |__cx|{
|
||||
let code_location = get_line_num!();
|
||||
let captured = #captured;
|
||||
let text = #rsx_text;
|
||||
|
||||
resolve_scope(code_location, text, captured, __cx)
|
||||
})
|
||||
};
|
||||
if let Some(cx) = captured.custom_context {
|
||||
quote::quote! {
|
||||
#cx.render(#lazy)
|
||||
}
|
||||
.into()
|
||||
} else {
|
||||
lazy.into()
|
||||
}
|
||||
}
|
||||
Err(err) => err.into_compile_error().into(),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "hot-reload"))]
|
||||
body.to_token_stream().into()
|
||||
let mut tokens = proc_macro2::TokenStream::new();
|
||||
body.to_tokens_without_template(&mut tokens);
|
||||
tokens.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user