mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-12-18 16:43:21 +00:00
047ed1e553
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.
108 lines
3.1 KiB
Rust
108 lines
3.1 KiB
Rust
use proc_macro::TokenStream;
|
|
use quote::ToTokens;
|
|
use syn::parse_macro_input;
|
|
|
|
mod inlineprops;
|
|
mod props;
|
|
|
|
// mod rsx;
|
|
use dioxus_rsx as rsx;
|
|
|
|
#[proc_macro]
|
|
pub fn format_args_f(input: TokenStream) -> TokenStream {
|
|
use rsx::*;
|
|
let item = parse_macro_input!(input as IfmtInput);
|
|
format_args_f_impl(item)
|
|
.unwrap_or_else(|err| err.to_compile_error())
|
|
.into()
|
|
}
|
|
|
|
#[proc_macro_derive(Props, attributes(props))]
|
|
pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
let input = parse_macro_input!(input as syn::DeriveInput);
|
|
match props::impl_my_derive(&input) {
|
|
Ok(output) => output.into(),
|
|
Err(error) => error.to_compile_error().into(),
|
|
}
|
|
}
|
|
|
|
/// The rsx! macro makes it easy for developers to write jsx-style markup in their components.
|
|
///
|
|
/// ## Complete Reference Guide:
|
|
/// ```ignore
|
|
#[doc = include_str!("../../../examples/rsx_usage.rs")]
|
|
/// ```
|
|
#[proc_macro]
|
|
pub fn rsx(s: TokenStream) -> TokenStream {
|
|
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) => {
|
|
let mut tokens = proc_macro2::TokenStream::new();
|
|
body.to_tokens_without_template(&mut tokens);
|
|
tokens.into()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The render! macro makes it easy for developers to write jsx-style markup in their components.
|
|
///
|
|
/// The render macro automatically renders rsx - making it unhygenic.
|
|
///
|
|
/// ## Complete Reference Guide:
|
|
/// ```ignore
|
|
#[doc = include_str!("../../../examples/rsx_usage.rs")]
|
|
/// ```
|
|
#[proc_macro]
|
|
pub fn render(s: TokenStream) -> TokenStream {
|
|
match syn::parse::<rsx::CallBody>(s) {
|
|
Err(err) => err.to_compile_error().into(),
|
|
Ok(body) => quote::quote! {
|
|
cx.render(#body)
|
|
}
|
|
.into_token_stream()
|
|
.into(),
|
|
}
|
|
}
|
|
|
|
/// Derive props for a component within the component definition.
|
|
///
|
|
/// This macro provides a simple transformation from `Scope<{}>` to `Scope<P>`,
|
|
/// removing some boilerplate when defining props.
|
|
///
|
|
/// You don't *need* to use this macro at all, but it can be helpful in cases where
|
|
/// you would be repeating a lot of the usual Rust boilerplate.
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// #[inline_props]
|
|
/// fn app(cx: Scope, bob: String) -> Element {
|
|
/// cx.render(rsx!("hello, {bob}"))
|
|
/// }
|
|
///
|
|
/// // is equivalent to
|
|
///
|
|
/// #[derive(PartialEq, Props)]
|
|
/// struct AppProps {
|
|
/// bob: String,
|
|
/// }
|
|
///
|
|
/// fn app(cx: Scope<AppProps>) -> Element {
|
|
/// cx.render(rsx!("hello, {bob}"))
|
|
/// }
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn inline_props(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
|
match syn::parse::<inlineprops::InlinePropsBody>(s) {
|
|
Err(e) => e.to_compile_error().into(),
|
|
Ok(s) => s.to_token_stream().into(),
|
|
}
|
|
}
|