wip: rethinking stack machine
This commit is contained in:
parent
70cd46dbb2
commit
62ae5d3bb9
|
@ -50,3 +50,10 @@ crates.io
|
|||
utilties
|
||||
js
|
||||
Dyon
|
||||
ssr
|
||||
docusarus
|
||||
docsite
|
||||
dom
|
||||
textarea
|
||||
noderefs
|
||||
wasm
|
||||
|
|
|
@ -1,43 +1,83 @@
|
|||
fn main() {}
|
||||
//! A tour of the rsx! macro
|
||||
//! ------------------------
|
||||
//!
|
||||
//! This example serves as an informal quick reference of all the things that the rsx! macro can do.
|
||||
//!
|
||||
//! A full in-depth reference guide is available at: https://www.notion.so/rsx-macro-basics-ef6e367dec124f4784e736d91b0d0b19
|
||||
//!
|
||||
//! ## Topics
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//! ### Elements
|
||||
//! - Create any element from its tag
|
||||
//! - Accept compile-safe attributes for each tag
|
||||
//! - Display documentation for elements
|
||||
//! - Arguments instead of String
|
||||
//! - Text
|
||||
//! - Inline Styles
|
||||
//!
|
||||
//! ## General Concepts
|
||||
//! - Iterators
|
||||
//! - Keys
|
||||
//! - Match statements
|
||||
//! - Conditional Rendering
|
||||
//!
|
||||
//! ### Events
|
||||
//! - Handle events with the "onXYZ" syntax
|
||||
//! - Closures can capture their environment with the 'a lifetime
|
||||
//!
|
||||
//!
|
||||
//! ### Components
|
||||
//! - Components can be made by specifying the name
|
||||
//! - Components can be referenced by path
|
||||
//! - Components may have optional parameters
|
||||
//! - Components may have their properties specified by spread syntax
|
||||
//! - Components may accept child nodes
|
||||
//! - Components that accept "onXYZ" get those closures bump allocated
|
||||
//!
|
||||
//! ### Fragments
|
||||
//! - Allow fragments using the built-in `Fragment` component
|
||||
//! - Accept a list of vnodes as children for a Fragment component
|
||||
//! - Allow keyed fragments in iterators
|
||||
//! - Allow top-level fragments
|
||||
//!
|
||||
fn main() {
|
||||
dioxus::webview::launch(Example);
|
||||
}
|
||||
|
||||
mod components {
|
||||
use baller::Baller;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
fn example() {
|
||||
let g = rsx! {
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
crate::components::baller::Baller {}
|
||||
baller::Baller {
|
||||
}
|
||||
Taller {
|
||||
a: "asd"
|
||||
}
|
||||
// Elements
|
||||
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// Components
|
||||
// ==============
|
||||
// Can accept any paths
|
||||
crate::baller::Baller {}
|
||||
baller::Baller { }
|
||||
baller::Baller {}
|
||||
Baller {
|
||||
// todo: manual props
|
||||
// {...BallerProps {}}
|
||||
}
|
||||
div {
|
||||
a: "asd",
|
||||
a: "asd",
|
||||
a: "asd",
|
||||
a: "asd",
|
||||
div {
|
||||
"asdas",
|
||||
"asdas",
|
||||
"asdas",
|
||||
"asdas",
|
||||
div {},
|
||||
div {
|
||||
class: "asdasd"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Can take properties
|
||||
Taller { a: "asd" }
|
||||
|
||||
// Can take optional properties
|
||||
Taller { a: "asd" }
|
||||
|
||||
// Can pass in props directly
|
||||
Taller { a: "asd" /* ..{props}*/ }
|
||||
|
||||
// Can take children
|
||||
Taller { a: "asd", div {} }
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
mod baller {
|
||||
use super::*;
|
||||
|
@ -57,4 +97,3 @@ mod components {
|
|||
let b = true;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -391,3 +391,101 @@ static Component: FC = |ctx, name: &str| {
|
|||
|
||||
}
|
||||
```
|
||||
|
||||
## Noderefs
|
||||
|
||||
How do we resolve noderefs in a world of patches? Patches _must_ be serializable, so if we do something like `Option<&RefCell<Slot>>`, then that must serialize as _something_ to indicate to a remote host that access to the node itself is desired. Our `Slot` type will need to be somewhat abstract.
|
||||
|
||||
If we add a new patch type called "BindRef" we could do something like:
|
||||
|
||||
```rust
|
||||
enum Patch {
|
||||
//...
|
||||
BindAsRef { raw_node: &RefCell<Option<Slot>> }
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
let node_ref = use_node_ref(&ctx);
|
||||
use_effect(&ctx, || {
|
||||
|
||||
}, []);
|
||||
div { ref: node_ref,
|
||||
"hello me"
|
||||
h3 {"yo dom"}
|
||||
}
|
||||
```
|
||||
|
||||
refs only work when you're native to the platform. it doesn't make sense to gain a ref when you're not native.
|
||||
|
||||
## In-sync or separate?
|
||||
|
||||
React makes refs - and protection against dom manipulation - work by modifying the real dom while diffing the virtual dom. This lets it bind real dom elements to the virtual dom elements. Dioxus currently does not do this, instead creating a list of changes for an interpreter to apply once diffing has completed.
|
||||
|
||||
This behavior fit dodrio well as all dom manipulations would occur batched. The original intention for this approach was to make it faster to read out of wasm and into JS. Dodrio is essentially performing the wasm job that wasm<->js for strings does. In theory, this particular optimization is not necessary.
|
||||
|
||||
https://github.com/fitzgen/dodrio/issues/77
|
||||
|
||||
This issue/pr on the dodrio repository points to a future where elements are held on to by the virtualdom.
|
||||
|
||||
Can we solve events, refs, and protection against 3rd party dom mutation all in one shot?
|
||||
|
||||
I think we can....
|
||||
|
||||
every node gets a globally unique ID
|
||||
|
||||
abstract the real dom
|
||||
|
||||
```rust
|
||||
|
||||
trait RealDom {
|
||||
type Node: RealNode;
|
||||
fn get_node(&self, id: u32) -> &Self::Node;
|
||||
fn get_node_mut(&mut self, id: u32) -> &mut Self::Node;
|
||||
fn replace_node();
|
||||
fn create_text_node();
|
||||
fn create_element();
|
||||
fn create_element_ns();
|
||||
}
|
||||
|
||||
trait RealNode {
|
||||
fn add_listener(&mut self, event: &str);
|
||||
fn set_inner_text(&mut self, text: &str);
|
||||
fn set_attr(&mut self, name, value);
|
||||
fn set_class(&mut self);
|
||||
fn remove_attr(&mut self);
|
||||
fn downcast_mut<T>(&mut self) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
impl VirtualDom<Dom: RealDom> {
|
||||
fn diff<Dom: RealDom>() {
|
||||
|
||||
}
|
||||
}
|
||||
enum VNode<'bump, 'realdom, RealDom> {
|
||||
VElement {
|
||||
real: &RealDom::Node
|
||||
}
|
||||
VText {
|
||||
real: &RealDom::Node
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut real_dom = websys::Document();
|
||||
let virtual_dom = Dioxus::VirtualDom::new();
|
||||
|
||||
virtual_dom.rebuild(&mut real_dom);
|
||||
|
||||
loop {
|
||||
let event = switch! {
|
||||
real_dom.events.await => event,
|
||||
virtual_dom.inner_events.await => event
|
||||
};
|
||||
|
||||
virtual_dom.apply_event(&mut real_dom, event);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
- [] Move the builder API onto NodeCtx
|
||||
- [] Transition away from names and towards compile-time safe tags
|
||||
- [] Fix diffing of fragments
|
||||
- [] Properly integrate memoization to prevent safety issues with children
|
||||
- [] Understand the issue with callbacks (outdated generations)
|
||||
- [] Fix examples for core, web, ssr, and general
|
||||
- [] Finish up documentation
|
||||
- [] Polish the Recoil (Dirac?) API
|
||||
- [] Find better names for things
|
||||
- [] get the html macro up to parity with the rsx! macro
|
||||
- [] put warnings in for iterating w/o keys
|
||||
- [] finish up the crate for generating code blocks
|
||||
- [] make progress on the docusarus-style crate for generating the websites
|
||||
- [] build the docsite
|
||||
- [] find a way to serialize the virtualdom completely
|
||||
- [] ...some how deserialize (hydrate) the dom state?
|
||||
- [] Implement controlled inputs for select and textarea
|
||||
- [] ...somehow... noderefs....
|
|
@ -50,14 +50,9 @@ impl Parse for AmbiguousElement {
|
|||
false => {
|
||||
let first_char = name_str.chars().next().unwrap();
|
||||
if first_char.is_ascii_uppercase() {
|
||||
match name_str.as_str() {
|
||||
"Fragment" => input
|
||||
.parse::<Fragment>()
|
||||
.map(|c| AmbiguousElement::Fragment(c)),
|
||||
_ => input
|
||||
input
|
||||
.parse::<Component>()
|
||||
.map(|c| AmbiguousElement::Component(c)),
|
||||
}
|
||||
.map(|c| AmbiguousElement::Component(c))
|
||||
} else {
|
||||
let name = input.parse::<Ident>().unwrap();
|
||||
Err(Error::new(
|
||||
|
|
|
@ -34,30 +34,16 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
|
|||
T::builder()
|
||||
}
|
||||
|
||||
mod eliminate_bounds {
|
||||
|
||||
struct BNode<'a> {
|
||||
_p: &'a (),
|
||||
}
|
||||
|
||||
trait Broper {}
|
||||
impl Broper for () {}
|
||||
|
||||
struct Bontext<'a, P: Broper + 'a> {
|
||||
inner: &'a (),
|
||||
props: P,
|
||||
}
|
||||
|
||||
fn Bexample(c: Bontext<()>) -> BNode {
|
||||
todo!()
|
||||
}
|
||||
|
||||
struct MyBrops<'a> {
|
||||
_i: &'a (),
|
||||
}
|
||||
impl<'a> Broper for MyBrops<'a> {}
|
||||
|
||||
fn Bexample2<'a>(c: Bontext<'a, MyBrops<'a>>) -> BNode {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
/// Create inline fragments
|
||||
/// --
|
||||
///
|
||||
/// Fragments capture a series of children without rendering extra nodes.
|
||||
///
|
||||
///
|
||||
///
|
||||
pub static Fragment: FC<()> = |ctx| {
|
||||
use crate::prelude::*;
|
||||
ctx.render(LazyNodes::new(move |c| {
|
||||
crate::nodebuilder::vfragment(c, None, ctx.children())
|
||||
}))
|
||||
};
|
||||
|
|
|
@ -50,7 +50,7 @@ pub(crate) mod innerlude {
|
|||
/// Re-export common types for ease of development use.
|
||||
/// Essential when working with the html! macro
|
||||
pub mod prelude {
|
||||
pub use crate::component::{fc_to_builder, Properties};
|
||||
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
||||
use crate::nodes;
|
||||
pub use crate::virtual_dom::Context;
|
||||
pub use crate::virtual_dom::Scoped;
|
||||
|
|
Loading…
Reference in New Issue