wip: it works but the page is backwards
This commit is contained in:
1 parent
a0a977a12d
commit
cdcd8611e8
19 files changed
+239
-349
No files matched your search
+20
-20
@@ -84,8 +84,8 @@ impl WebsysDom {
|
||||
DomEdit::PushRoot { id: root } => self.push(root),
|
||||
DomEdit::PopRoot => self.pop(),
|
||||
DomEdit::AppendChildren { many } => self.append_children(many),
|
||||
DomEdit::ReplaceWith { n, m } => self.replace_with(n, m),
|
||||
DomEdit::Remove => self.remove(),
|
||||
DomEdit::ReplaceWith { m, root } => self.replace_with(m, root),
|
||||
DomEdit::Remove { root } => self.remove(root),
|
||||
DomEdit::RemoveAllChildren => self.remove_all_children(),
|
||||
DomEdit::CreateTextNode { text, id } => self.create_text_node(text, id),
|
||||
DomEdit::CreateElement { tag, id } => self.create_element(tag, None, id),
|
||||
@@ -102,8 +102,8 @@ impl WebsysDom {
|
||||
DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns),
|
||||
DomEdit::RemoveAttribute { name } => self.remove_attribute(name),
|
||||
|
||||
DomEdit::InsertAfter { n } => self.insert_after(n),
|
||||
DomEdit::InsertBefore { n } => self.insert_before(n),
|
||||
DomEdit::InsertAfter { n, root } => self.insert_after(n, root),
|
||||
DomEdit::InsertBefore { n, root } => self.insert_before(n, root),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ impl WebsysDom {
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_with(&mut self, n: u32, m: u32) {
|
||||
fn replace_with(&mut self, m: u32, root: u64) {
|
||||
log::debug!("Called [`replace_with`]");
|
||||
|
||||
let mut new_nodes = vec![];
|
||||
@@ -162,19 +162,11 @@ impl WebsysDom {
|
||||
new_nodes.push(self.stack.pop());
|
||||
}
|
||||
|
||||
let mut old_nodes = vec![];
|
||||
for _ in 0..n {
|
||||
old_nodes.push(self.stack.pop());
|
||||
}
|
||||
|
||||
for node in &old_nodes[1..] {
|
||||
node.dyn_ref::<Element>().unwrap().remove();
|
||||
}
|
||||
|
||||
let old = old_nodes[0].clone();
|
||||
let old = self.nodes[root as usize].as_ref().unwrap();
|
||||
let arr: js_sys::Array = new_nodes.iter().collect();
|
||||
let el = old.dyn_into::<Element>().unwrap();
|
||||
let el = old.dyn_ref::<Element>().unwrap();
|
||||
el.replace_with_with_node(&arr).unwrap();
|
||||
|
||||
// let arr = js_sys::Array::from();
|
||||
|
||||
// TODO: use different-sized replace withs
|
||||
@@ -205,9 +197,17 @@ impl WebsysDom {
|
||||
// self.stack.push(new_node);
|
||||
}
|
||||
|
||||
fn remove(&mut self) {
|
||||
fn remove(&mut self, root: u64) {
|
||||
log::debug!("Called [`remove`]");
|
||||
todo!()
|
||||
|
||||
let node = self.nodes[root as usize].as_ref().unwrap();
|
||||
if let Some(element) = node.dyn_ref::<Element>() {
|
||||
element.remove();
|
||||
} else {
|
||||
if let Some(parent) = node.parent_node() {
|
||||
parent.remove_child(&node).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_all_children(&mut self) {
|
||||
@@ -361,7 +361,7 @@ impl WebsysDom {
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_after(&mut self, n: u32) {
|
||||
fn insert_after(&mut self, n: u32, root: u64) {
|
||||
let mut new_nodes = vec![];
|
||||
for _ in 0..n {
|
||||
new_nodes.push(self.stack.pop());
|
||||
@@ -380,7 +380,7 @@ impl WebsysDom {
|
||||
// let el = self.stack.top();
|
||||
}
|
||||
|
||||
fn insert_before(&mut self, n: u32) {
|
||||
fn insert_before(&mut self, n: u32, root: u64) {
|
||||
let n = n as usize;
|
||||
let root = self
|
||||
.stack
|
||||
|
||||
+64
-41
@@ -1,30 +1,56 @@
|
||||
//! Dioxus WebSys
|
||||
//! --------------
|
||||
//! This crate implements a renderer of the Dioxus Virtual DOM for the web browser using Websys.
|
||||
|
||||
/*
|
||||
From Google's guide on rAF and rIC:
|
||||
--------
|
||||
|
||||
If the callback is fired at the end of the frame, it will be scheduled to go after the current frame has been committed,
|
||||
which means that style changes will have been applied, and, importantly, layout calculated. If we make DOM changes inside
|
||||
of the idle callback, those layout calculations will be invalidated. If there are any kind of layout reads in the next
|
||||
frame, e.g. getBoundingClientRect, clientWidth, etc, the browser will have to perform a Forced Synchronous Layout,
|
||||
which is a potential performance bottleneck.
|
||||
|
||||
Another reason not trigger DOM changes in the idle callback is that the time impact of changing the DOM is unpredictable,
|
||||
and as such we could easily go past the deadline the browser provided.
|
||||
|
||||
The best practice is to only make DOM changes inside of a requestAnimationFrame callback, since it is scheduled by the
|
||||
browser with that type of work in mind. That means that our code will need to use a document fragment, which can then
|
||||
be appended in the next requestAnimationFrame callback. If you are using a VDOM library, you would use requestIdleCallback
|
||||
to make changes, but you would apply the DOM patches in the next requestAnimationFrame callback, not the idle callback.
|
||||
|
||||
Essentially:
|
||||
------------
|
||||
- Do the VDOM work during the idlecallback
|
||||
- Do DOM work in the next requestAnimationFrame callback
|
||||
*/
|
||||
//!
|
||||
//! ## Overview
|
||||
//! ------------
|
||||
//! This crate implements a renderer of the Dioxus Virtual DOM for the web browser using WebSys. This web render for
|
||||
//! Dioxus is one of the more advanced renderers, supporting:
|
||||
//! - idle work
|
||||
//! - animations
|
||||
//! - jank-free rendering
|
||||
//! - noderefs
|
||||
//! - controlled components
|
||||
//! - re-hydration
|
||||
//! - and more.
|
||||
//!
|
||||
//! The actual implementation is farily thin, with the heavy lifting happening inside the Dioxus Core crate.
|
||||
//!
|
||||
//! To purview the examples, check of the root Dioxus crate - the examples in this crate are mostly meant to provide
|
||||
//! validation of websys-specific features and not the general use of Dioxus.
|
||||
//!
|
||||
//! ## RequestAnimationFrame and RequestIdleCallback
|
||||
//! ------------------------------------------------
|
||||
//! React implements "jank free rendering" by deliberately not blocking the browser's main thread. For large diffs, long
|
||||
//! running work, and integration with things like React-Three-Fiber, it's extremeley important to avoid blocking the
|
||||
//! main thread.
|
||||
//!
|
||||
//! React solves this problem by breaking up the rendering process into a "diff" phase and a "render" phase. In Dioxus,
|
||||
//! the diff phase is non-blocking, using "yield_now" to allow the browser to process other events. When the diff phase
|
||||
//! is finally complete, the VirtualDOM will return a set of "Mutations" for this crate to apply.
|
||||
//!
|
||||
//! Here, we schedule the "diff" phase during the browser's idle period, achieved by calling RequestIdleCallback and then
|
||||
//! setting a timeout from the that completes when the idleperiod is over. Then, we call requestAnimationFrame
|
||||
//!
|
||||
//! From Google's guide on rAF and rIC:
|
||||
//! -----------------------------------
|
||||
//!
|
||||
//! If the callback is fired at the end of the frame, it will be scheduled to go after the current frame has been committed,
|
||||
//! which means that style changes will have been applied, and, importantly, layout calculated. If we make DOM changes inside
|
||||
//! of the idle callback, those layout calculations will be invalidated. If there are any kind of layout reads in the next
|
||||
//! frame, e.g. getBoundingClientRect, clientWidth, etc, the browser will have to perform a Forced Synchronous Layout,
|
||||
//! which is a potential performance bottleneck.
|
||||
//!
|
||||
//! Another reason not trigger DOM changes in the idle callback is that the time impact of changing the DOM is unpredictable,
|
||||
//! and as such we could easily go past the deadline the browser provided.
|
||||
//!
|
||||
//! The best practice is to only make DOM changes inside of a requestAnimationFrame callback, since it is scheduled by the
|
||||
//! browser with that type of work in mind. That means that our code will need to use a document fragment, which can then
|
||||
//! be appended in the next requestAnimationFrame callback. If you are using a VDOM library, you would use requestIdleCallback
|
||||
//! to make changes, but you would apply the DOM patches in the next requestAnimationFrame callback, not the idle callback.
|
||||
//!
|
||||
//! Essentially:
|
||||
//! ------------
|
||||
//! - Do the VDOM work during the idlecallback
|
||||
//! - Do DOM work in the next requestAnimationFrame callback
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -103,20 +129,22 @@ pub async fn run_with_props<T: Properties + 'static>(
|
||||
) -> Result<()> {
|
||||
let mut dom = VirtualDom::new_with_props(root, root_props);
|
||||
|
||||
let hydrating = cfg.hydrate;
|
||||
|
||||
let root_el = load_document().get_element_by_id(&cfg.rootname).unwrap();
|
||||
|
||||
let tasks = dom.get_event_sender();
|
||||
let sender_callback = Rc::new(move |event| tasks.unbounded_send(event).unwrap());
|
||||
|
||||
// initialize the virtualdom first
|
||||
// if cfg.hydrate {
|
||||
// dom.rebuild_in_place()?;
|
||||
// }
|
||||
let mut websys_dom = dom::WebsysDom::new(root_el, cfg, sender_callback);
|
||||
|
||||
let mut websys_dom = dom::WebsysDom::new(
|
||||
root_el,
|
||||
cfg,
|
||||
Rc::new(move |event| tasks.unbounded_send(event).unwrap()),
|
||||
);
|
||||
let mut mutations = dom.rebuild().unwrap();
|
||||
log::info!("Mutations: {:#?}", mutations);
|
||||
|
||||
// hydrating is simply running the dom for a single render. If the page is already written, then the corresponding
|
||||
// ElementIds should already line up because the web_sys dom has already loaded elements with the DioxusID into memory
|
||||
if !hydrating {
|
||||
websys_dom.process_edits(&mut mutations.edits);
|
||||
}
|
||||
|
||||
loop {
|
||||
let deadline = gloo_timers::future::TimeoutFuture::new(16);
|
||||
@@ -127,8 +155,3 @@ pub async fn run_with_props<T: Properties + 'static>(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct HydrationNode {
|
||||
id: usize,
|
||||
node: Node,
|
||||
}
|
||||
Reference in new issue
Block a user