diff --git a/packages/core/.vscode/spellright.dict b/packages/core/.vscode/spellright.dict index c0214aff..bee781eb 100644 --- a/packages/core/.vscode/spellright.dict +++ b/packages/core/.vscode/spellright.dict @@ -4,3 +4,5 @@ dom virtualdom ns nohasher +Preact +vnodes diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index c7767b52..c77791ed 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -33,6 +33,7 @@ log = "0.4" # Serialize the Edits for use in Webview/Liveview instances serde = { version="1", features=["derive"], optional=true } +smallvec = "1.6.1" [features] default = [] diff --git a/packages/core/README.md b/packages/core/README.md index c08206f0..b88a595e 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -12,6 +12,19 @@ Dioxus-core builds off the many frameworks that came before it. Notably, Dioxus - Dodrio: bump allocation, double buffering, and source code for NodeBuilder - Percy: html! macro architecture, platform-agnostic edits - Yew: passion and inspiration ❤️ +- InfernoJS: approach to fragments and node diffing +- Preact: approach for normalization and ref + +Dioxus-core leverages some really cool techniques and hits a very high level of parity with mature frameworks. Some unique features include: + +- managed lifetimes for borrowed data +- suspended nodes (task/fiber endpoints) for asynchronous vnodes +- custom memory allocator for vnodes and all text content +- support for fragments w/ lazy normalization + +There's certainly more to the story, but these optimizations make Dioxus memory use and allocation count extremely minimal. For an average application, it is likely that zero allocations will need to be performed once the app has been mounted. Only when new components are added to the dom will allocations occur - and only en mass. The space of old VNodes is dynamically recycled as new nodes are added. Additionally, Dioxus tracks the average memory footprint of previous components to estimate how much memory allocate for future components. + +All in all, Dioxus treats memory as an incredibly valuable resource. Combined with the memory-efficient footprint of WASM compilation, Dioxus apps can scale to thousands of components and still stay snappy and respect your RAM usage. ## Goals @@ -31,40 +44,36 @@ We have big goals for Dioxus. The final implementation must: - Support lazy VNodes (ie VNodes that are not actually created when the html! macro is used) - Support advanced diffing strategies (patience, Meyers, etc) -## Design Quirks - -- Use of "Context" as a way of mitigating threading issues and the borrow checker. (JS relies on globals) -- html! is lazy - needs to be used with a partner function to actually allocate the html. (Good be a good thing or a bad thing) - -```rust -let text = TextRenderer::render(html! {
"hello world"
}); -//
hello world
-``` - ```rust -fn main() { - tide::new() - .get("blah", serve_app("../")) - .get("blah", ws_handler(serve_app)) +rsx!{ "this is a text node" } + +rsx!{ + div {} + "asd" + div {} + div {} +} +rsx!{ + div { + a {} + b {} + c {} + Container { + Container { + Container { + Container { + Container { + div {} + } + } + } + } + } + } } -fn serve_app(ctx: &Context<()>) -> VNode { - let livecontext = LiveContext::new() - .with_handler("graph", graph_component) - .with_handler("graph", graph_component) - .with_handler("graph", graph_component) - .with_handler("graph", graph_component) - .with_handler("graph", graph_component) - .with_handler("graph", graph_component) - .build(); - ctx.render(html! { - - - - }) -} ``` diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 409ca6c8..d5aa86c6 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -95,14 +95,6 @@ pub struct DiffMachine<'a, Dom: RealDom> { pub seen_nodes: FxHashSet, } -// // todo: see if unsafe works better -// static COUNTER: Cell = Cell::new(1); -// fn next_id() -> u32 { -// let out = COUNTER.get(); -// COUNTER.set(out + 1); -// out -// } - impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { pub fn new( dom: &'a mut Dom, @@ -262,21 +254,32 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { } } - VNode::Fragment(_) => match new_node { - VNode::Fragment(_) => todo!(), - VNode::Element(_) => todo!(), - VNode::Text(_) => todo!(), - VNode::Suspended => todo!(), - VNode::Component(_) => todo!(), - }, + VNode::Fragment(old) => { + // + match new_node { + VNode::Fragment(_) => todo!(), - VNode::Suspended => match new_node { - VNode::Suspended => todo!(), - VNode::Element(_) => todo!(), - VNode::Text(_) => todo!(), - VNode::Fragment(_) => todo!(), - VNode::Component(_) => todo!(), - }, + // going from fragment to element means we're going from many (or potentially none) to one + VNode::Element(new) => {} + VNode::Text(_) => todo!(), + VNode::Suspended => todo!(), + VNode::Component(_) => todo!(), + } + } + + // a suspended node will perform a mem-copy of the previous elements until it is ready + // this means that event listeners will need to be disabled and removed + // it also means that props will need to disabled - IE if the node "came out of hibernation" any props should be considered outdated + VNode::Suspended => { + // + match new_node { + VNode::Suspended => todo!(), + VNode::Element(_) => todo!(), + VNode::Text(_) => todo!(), + VNode::Fragment(_) => todo!(), + VNode::Component(_) => todo!(), + } + } } }