chore: clean up web impl

This commit is contained in:
Jonathan Kelley committed 2022-11-30 17:44:00 -05:00
1 parent 18d6b1ad6f
commit ba26b1001a
3 files changed
+60 -68

No files matched your search

-7
View File
@@ -118,13 +118,6 @@ impl WebsysDom {
} }
} }
pub struct DioxusWebsysEvent(web_sys::Event);
// safety: currently the web is not multithreaded and our VirtualDom exists on the same thread
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for DioxusWebsysEvent {}
unsafe impl Sync for DioxusWebsysEvent {}
// todo: some of these events are being casted to the wrong event type. // todo: some of these events are being casted to the wrong event type.
// We need tests that simulate clicks/etc and make sure every event type works. // We need tests that simulate clicks/etc and make sure every event type works.
pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -> Rc<dyn Any> { pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -> Rc<dyn Any> {
+24 -9
View File
@@ -1,11 +1,24 @@
use dioxus_core::SchedulerMsg; #![allow(dead_code)]
use dioxus_core::SetTemplateMsg;
use dioxus_core::VirtualDom; use futures_channel::mpsc::UnboundedReceiver;
use wasm_bindgen::closure::Closure; use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::{MessageEvent, WebSocket}; use web_sys::{MessageEvent, WebSocket};
pub(crate) fn init(dom: &VirtualDom) { #[cfg(not(debug_assertions))]
pub(crate) fn init() -> UnboundedReceiver<String> {
let (tx, rx) = futures_channel::mpsc::unbounded();
std::mem::forget(tx);
rx
}
#[cfg(debug_assertions)]
pub(crate) fn init() -> UnboundedReceiver<String> {
use std::convert::TryInto;
let window = web_sys::window().unwrap(); let window = web_sys::window().unwrap();
let protocol = if window.location().protocol().unwrap() == "https:" { let protocol = if window.location().protocol().unwrap() == "https:" {
@@ -20,18 +33,20 @@ pub(crate) fn init(dom: &VirtualDom) {
); );
let ws = WebSocket::new(&url).unwrap(); let ws = WebSocket::new(&url).unwrap();
let mut channel = dom.get_scheduler_channel();
let (tx, rx) = futures_channel::mpsc::unbounded();
// change the rsx when new data is received // change the rsx when new data is received
let cl = Closure::wrap(Box::new(move |e: MessageEvent| { let cl = Closure::wrap(Box::new(move |e: MessageEvent| {
if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() { if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() {
let msg: SetTemplateMsg = serde_json::from_str(&format!("{text}")).unwrap(); if let Ok(val) = text.try_into() {
channel _ = tx.unbounded_send(val);
.start_send(SchedulerMsg::SetTemplate(Box::new(msg))) }
.unwrap();
} }
}) as Box<dyn FnMut(MessageEvent)>); }) as Box<dyn FnMut(MessageEvent)>);
ws.set_onmessage(Some(cl.as_ref().unchecked_ref())); ws.set_onmessage(Some(cl.as_ref().unchecked_ref()));
cl.forget(); cl.forget();
rx
} }
+36 -52
View File
@@ -9,9 +9,8 @@
//! - idle work //! - idle work
//! - animations //! - animations
//! - jank-free rendering //! - jank-free rendering
//! - noderefs
//! - controlled components //! - controlled components
//! - re-hydration //! - hydration
//! - and more. //! - and more.
//! //!
//! The actual implementation is farily thin, with the heavy lifting happening inside the Dioxus Core crate. //! The actual implementation is farily thin, with the heavy lifting happening inside the Dioxus Core crate.
@@ -54,24 +53,22 @@
// - Do the VDOM work during the idlecallback // - Do the VDOM work during the idlecallback
// - Do DOM work in the next requestAnimationFrame callback // - Do DOM work in the next requestAnimationFrame callback
use std::{rc::Rc, time::Duration}; use std::time::Duration;
pub use crate::cfg::Config; pub use crate::cfg::Config;
use crate::dom::virtual_event_from_websys_event; use crate::dom::virtual_event_from_websys_event;
pub use crate::util::use_eval; pub use crate::util::use_eval;
use dioxus_core::{Element, ElementId, Scope, VirtualDom}; use dioxus_core::{Element, ElementId, Scope, VirtualDom};
use futures_channel::mpsc::unbounded;
use futures_util::{pin_mut, FutureExt, StreamExt}; use futures_util::{pin_mut, FutureExt, StreamExt};
use gloo_timers::future::sleep; use gloo_timers::future::sleep;
use web_sys::Event;
mod cache; mod cache;
mod cfg; mod cfg;
mod dom; mod dom;
// #[cfg(any(feature = "hot-reload", debug_assertions))] mod hot_reload;
// mod hot_reload;
// #[cfg(feature = "hydrate")]
// mod rehydrate; // mod rehydrate;
// mod ric_raf; mod ric_raf;
mod util; mod util;
/// Launch the VirtualDOM given a root component and a configuration. /// Launch the VirtualDOM given a root component and a configuration.
@@ -175,8 +172,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
} }
// #[cfg(any(feature = "hot-reload", debug_assertions))] let mut hotreload_rx = hot_reload::init();
// hot_reload::init(&dom);
for s in crate::cache::BUILTIN_INTERNED_STRINGS { for s in crate::cache::BUILTIN_INTERNED_STRINGS {
wasm_bindgen::intern(s); wasm_bindgen::intern(s);
@@ -185,7 +181,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
wasm_bindgen::intern(s); wasm_bindgen::intern(s);
} }
// a let should_hydrate = cfg.hydrate; let should_hydrate = cfg.hydrate;
let (tx, mut rx) = futures_channel::mpsc::unbounded(); let (tx, mut rx) = futures_channel::mpsc::unbounded();
@@ -193,30 +189,39 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
log::info!("rebuilding app"); log::info!("rebuilding app");
let edits = dom.rebuild(); if should_hydrate {
websys_dom.apply_edits(edits.template_mutations); } else {
websys_dom.apply_edits(edits.edits); let edits = dom.rebuild();
websys_dom.apply_edits(edits.template_mutations);
websys_dom.apply_edits(edits.edits);
}
let mut work_loop = ric_raf::RafLoop::new();
loop { loop {
log::trace!("waiting for work"); log::trace!("waiting for work");
// if virtualdom has nothing, wait for it to have something before requesting idle time // if virtualdom has nothing, wait for it to have something before requesting idle time
// if there is work then this future resolves immediately. // if there is work then this future resolves immediately.
let mut res = { let mut res = {
let work = dom.wait_for_work().fuse(); let work = dom.wait_for_work().fuse();
pin_mut!(work); pin_mut!(work);
futures_util::select! { futures_util::select! {
_ = work => None, _ = work => None,
new_template = hotreload_rx.next() => {
todo!("Implement hot reload");
None
}
evt = rx.next() => evt evt = rx.next() => evt
} }
}; };
// Dequeue all of the events from the channel in send order
// todo: we should re-order these if possible
while let Some(evt) = res { while let Some(evt) = res {
let name = evt.type_(); let name = evt.type_();
let element = walk_event_for_id(&evt); let element = walk_event_for_id(&evt);
let bubbles = dioxus_html::event_bubbles(name.as_str()); let bubbles = dioxus_html::event_bubbles(name.as_str());
if let Some((element, target)) = element { if let Some((element, target)) = element {
let data = virtual_event_from_websys_event(evt, target); let data = virtual_event_from_websys_event(evt, target);
dom.handle_event(name.as_str(), data, element, bubbles); dom.handle_event(name.as_str(), data, element, bubbles);
@@ -224,57 +229,38 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
res = rx.try_next().transpose().unwrap().ok(); res = rx.try_next().transpose().unwrap().ok();
} }
let deadline = sleep(Duration::from_millis(50)); // Jank free rendering
//
let edits = dom.render_with_deadline(deadline).await; // 1. wait for the browser to give us "idle" time
// 2. During idle time, diff the dom
log::trace!("working.."); // 3. Stop diffing if the deadline is exceded
// 4. Wait for the animation frame to patch the dom
// wait for the mainthread to schedule us in // wait for the mainthread to schedule us in
// let mut deadline = work_loop.wait_for_idle_time().await; let deadline = work_loop.wait_for_idle_time().await;
// run the virtualdom work phase until the frame deadline is reached // run the virtualdom work phase until the frame deadline is reached
// let mutations = dom.work_with_deadline(|| (&mut deadline).now_or_never().is_some()); let edits = dom.render_with_deadline(deadline).await;
// wait for the animation frame to fire so we can apply our changes // wait for the animation frame to fire so we can apply our changes
// work_loop.wait_for_raf().await; work_loop.wait_for_raf().await;
log::debug!("edits {:#?}", edits);
// for edit in mutations {
// // actually apply our changes during the animation frame
websys_dom.apply_edits(edits.template_mutations); websys_dom.apply_edits(edits.template_mutations);
websys_dom.apply_edits(edits.edits); websys_dom.apply_edits(edits.edits);
// }
} }
} }
fn walk_event_for_id(event: &Event) -> Option<(ElementId, web_sys::Element)> { fn walk_event_for_id(event: &web_sys::Event) -> Option<(ElementId, web_sys::Element)> {
use wasm_bindgen::{closure::Closure, JsCast, JsValue}; use wasm_bindgen::JsCast;
use web_sys::{Document, Element, Event, HtmlElement};
let mut target = event let mut target = event
.target() .target()
.expect("missing target") .expect("missing target")
.dyn_into::<Element>() .dyn_into::<web_sys::Element>()
.expect("not a valid element"); .expect("not a valid element");
// break Ok(UserEvent {
// name: event_name_from_typ(&typ),
// data: virtual_event_from_websys_event(event.clone(), target.clone()),
// element: Some(ElementId(id)),
// scope_id: None,
// priority: dioxus_core::EventPriority::Medium,
// bubbles: event.bubbles(),
// });
// break Ok(UserEvent {
// name: event_name_from_typ(&typ),
// data: virtual_event_from_websys_event(event.clone(), target.clone()),
// element: None,
// scope_id: None,
// priority: dioxus_core::EventPriority::Low,
// bubbles: event.bubbles(),
// });
loop { loop {
match target.get_attribute("data-dioxus-id").map(|f| f.parse()) { match target.get_attribute("data-dioxus-id").map(|f| f.parse()) {
Some(Ok(id)) => return Some((ElementId(id), target)), Some(Ok(id)) => return Some((ElementId(id), target)),
@@ -315,5 +301,3 @@ fn walk_event_for_id(event: &Event) -> Option<(ElementId, web_sys::Element)> {
// websys_dom.apply_edits(edits.template_mutations); // websys_dom.apply_edits(edits.template_mutations);
// websys_dom.apply_edits(edits.edits); // websys_dom.apply_edits(edits.edits);
// } // }
// let mut work_loop = ric_raf::RafLoop::new();