chore: clean up web impl
This commit is contained in:
parent
18d6b1ad6f
commit
ba26b1001a
|
@ -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.
|
||||
// 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> {
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
use dioxus_core::SchedulerMsg;
|
||||
use dioxus_core::SetTemplateMsg;
|
||||
use dioxus_core::VirtualDom;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use futures_channel::mpsc::UnboundedReceiver;
|
||||
|
||||
use wasm_bindgen::closure::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
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 protocol = if window.location().protocol().unwrap() == "https:" {
|
||||
|
@ -20,18 +33,20 @@ pub(crate) fn init(dom: &VirtualDom) {
|
|||
);
|
||||
|
||||
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
|
||||
let cl = Closure::wrap(Box::new(move |e: MessageEvent| {
|
||||
if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() {
|
||||
let msg: SetTemplateMsg = serde_json::from_str(&format!("{text}")).unwrap();
|
||||
channel
|
||||
.start_send(SchedulerMsg::SetTemplate(Box::new(msg)))
|
||||
.unwrap();
|
||||
if let Ok(val) = text.try_into() {
|
||||
_ = tx.unbounded_send(val);
|
||||
}
|
||||
}
|
||||
}) as Box<dyn FnMut(MessageEvent)>);
|
||||
|
||||
ws.set_onmessage(Some(cl.as_ref().unchecked_ref()));
|
||||
cl.forget();
|
||||
|
||||
rx
|
||||
}
|
||||
|
|
|
@ -9,9 +9,8 @@
|
|||
//! - idle work
|
||||
//! - animations
|
||||
//! - jank-free rendering
|
||||
//! - noderefs
|
||||
//! - controlled components
|
||||
//! - re-hydration
|
||||
//! - hydration
|
||||
//! - and more.
|
||||
//!
|
||||
//! 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 DOM work in the next requestAnimationFrame callback
|
||||
|
||||
use std::{rc::Rc, time::Duration};
|
||||
use std::time::Duration;
|
||||
|
||||
pub use crate::cfg::Config;
|
||||
use crate::dom::virtual_event_from_websys_event;
|
||||
pub use crate::util::use_eval;
|
||||
use dioxus_core::{Element, ElementId, Scope, VirtualDom};
|
||||
use futures_channel::mpsc::unbounded;
|
||||
use futures_util::{pin_mut, FutureExt, StreamExt};
|
||||
use gloo_timers::future::sleep;
|
||||
use web_sys::Event;
|
||||
|
||||
mod cache;
|
||||
mod cfg;
|
||||
mod dom;
|
||||
// #[cfg(any(feature = "hot-reload", debug_assertions))]
|
||||
// mod hot_reload;
|
||||
// #[cfg(feature = "hydrate")]
|
||||
mod hot_reload;
|
||||
// mod rehydrate;
|
||||
// mod ric_raf;
|
||||
mod ric_raf;
|
||||
mod util;
|
||||
|
||||
/// 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();
|
||||
}
|
||||
|
||||
// #[cfg(any(feature = "hot-reload", debug_assertions))]
|
||||
// hot_reload::init(&dom);
|
||||
let mut hotreload_rx = hot_reload::init();
|
||||
|
||||
for s in crate::cache::BUILTIN_INTERNED_STRINGS {
|
||||
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);
|
||||
}
|
||||
|
||||
// a let should_hydrate = cfg.hydrate;
|
||||
let should_hydrate = cfg.hydrate;
|
||||
|
||||
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");
|
||||
|
||||
let edits = dom.rebuild();
|
||||
websys_dom.apply_edits(edits.template_mutations);
|
||||
websys_dom.apply_edits(edits.edits);
|
||||
if should_hydrate {
|
||||
} else {
|
||||
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 {
|
||||
log::trace!("waiting for work");
|
||||
|
||||
// if virtualdom has nothing, wait for it to have something before requesting idle time
|
||||
// if there is work then this future resolves immediately.
|
||||
|
||||
let mut res = {
|
||||
let work = dom.wait_for_work().fuse();
|
||||
pin_mut!(work);
|
||||
|
||||
futures_util::select! {
|
||||
_ = work => None,
|
||||
new_template = hotreload_rx.next() => {
|
||||
todo!("Implement hot reload");
|
||||
None
|
||||
}
|
||||
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 {
|
||||
let name = evt.type_();
|
||||
let element = walk_event_for_id(&evt);
|
||||
let bubbles = dioxus_html::event_bubbles(name.as_str());
|
||||
|
||||
if let Some((element, target)) = element {
|
||||
let data = virtual_event_from_websys_event(evt, target);
|
||||
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();
|
||||
}
|
||||
|
||||
let deadline = sleep(Duration::from_millis(50));
|
||||
|
||||
let edits = dom.render_with_deadline(deadline).await;
|
||||
|
||||
log::trace!("working..");
|
||||
// Jank free rendering
|
||||
//
|
||||
// 1. wait for the browser to give us "idle" time
|
||||
// 2. During idle time, diff the dom
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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.edits);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_event_for_id(event: &Event) -> Option<(ElementId, web_sys::Element)> {
|
||||
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
||||
use web_sys::{Document, Element, Event, HtmlElement};
|
||||
fn walk_event_for_id(event: &web_sys::Event) -> Option<(ElementId, web_sys::Element)> {
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
let mut target = event
|
||||
.target()
|
||||
.expect("missing target")
|
||||
.dyn_into::<Element>()
|
||||
.dyn_into::<web_sys::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 {
|
||||
match target.get_attribute("data-dioxus-id").map(|f| f.parse()) {
|
||||
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.edits);
|
||||
// }
|
||||
|
||||
// let mut work_loop = ric_raf::RafLoop::new();
|
||||
|
|
Loading…
Reference in New Issue