Chore: remove old cruft in web crate (#2957)

This commit is contained in:
Jonathan Kelley 2024-09-13 12:54:28 -07:00 committed by GitHub
parent c7124e41fb
commit c5f00bf7d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 0 additions and 303 deletions

View file

@ -1,35 +0,0 @@
// ## 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 extremely 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 "work_with_deadline" 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

View file

@ -1,10 +0,0 @@
Examples
========
# Hydrate
- `hydrate` show hydrate
# Async
- `timeout_count` button to add count and show count in the future

View file

@ -1,57 +0,0 @@
use dioxus::prelude::*;
use dioxus_web::Config;
use web_sys::window;
fn app() -> Element {
rsx! {
div { h1 { "thing 1" } }
div { h2 { "thing 2" } }
div {
h2 { "thing 2" }
"asd"
"asd"
Bapp {}
}
{(0..10).map(|f| rsx! {
div {
"thing {f}"
}
})}
}
}
#[allow(non_snake_case)]
fn Bapp() -> Element {
rsx! {
div { h1 { "thing 1" } }
div { h2 { "thing 2" } }
div {
h2 { "thing 2" }
"asd"
"asd"
}
}
}
fn main() {
console_error_panic_hook::set_once();
tracing_wasm::set_as_global_default();
let mut dom = VirtualDom::new(app);
dom.rebuild(&mut dioxus_core::NoOpMutations);
let pre = dioxus_ssr::pre_render(&dom);
tracing::trace!("{}", pre);
// set the inner content of main to the pre-rendered content
window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("main")
.unwrap()
.set_inner_html(&pre);
// now rehydrate
dioxus_web::launch::launch(app, vec![], Config::new().hydrate(true));
}

View file

@ -1,34 +0,0 @@
// https://jakelazaroff.com/words/were-react-hooks-a-mistake/
use dioxus::prelude::*;
fn main() {
dioxus_web::launch::launch(app, vec![], Default::default());
}
fn app() -> Element {
let mut count = use_signal(|| 0);
let mut started = use_signal(|| false);
let mut start = move || {
if !started() {
let alert = move || gloo_dialogs::alert(&format!("Your score was {count}!",));
gloo_timers::callback::Timeout::new(5_000, alert).forget();
}
started.set(true); // this cannot be done inside condition or infinite loop
};
rsx! {
button {
onclick: move |_event| {
start();
count += 1;
},
if started() {
"Current score: {count}"
} else {
"Start"
}
}
}
}

View file

@ -1,3 +0,0 @@
requestIdleCallback and requestAnimationFrame implementation
These currently actually slow down our DOM patching and thus are temporarily removed. Technically we can schedule around rIC and rAF but choose not to.

View file

@ -1,80 +0,0 @@
//! This module provides some utilities around scheduling tasks on the main thread of the browser.
//!
//! The ultimate goal here is to not block the main thread during animation frames, so our animations don't result in "jank".
//!
//! Hence, this module provides Dioxus "Jank Free Rendering" on the web.
//!
//! Because RIC doesn't work on Safari, we polyfill using the "ricpolyfill.js" file and use some basic detection to see
//! if RIC is available.
use futures_util::StreamExt;
use gloo_timers::future::TimeoutFuture;
use js_sys::Function;
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
use web_sys::{window, Window};
pub(crate) struct RafLoop {
window: Window,
ric_receiver: futures_channel::mpsc::UnboundedReceiver<u32>,
raf_receiver: futures_channel::mpsc::UnboundedReceiver<()>,
ric_closure: Closure<dyn Fn(JsValue)>,
raf_closure: Closure<dyn Fn(JsValue)>,
}
impl RafLoop {
pub fn new() -> Self {
let (raf_sender, raf_receiver) = futures_channel::mpsc::unbounded();
let raf_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |_v: JsValue| {
raf_sender.unbounded_send(()).unwrap()
}));
let (ric_sender, ric_receiver) = futures_channel::mpsc::unbounded();
let has_idle_callback = {
let bo = window().unwrap().dyn_into::<js_sys::Object>().unwrap();
bo.has_own_property(&JsValue::from_str("requestIdleCallback"))
};
let ric_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |v: JsValue| {
let time_remaining = if has_idle_callback {
if let Ok(deadline) = v.dyn_into::<web_sys::IdleDeadline>() {
deadline.time_remaining() as u32
} else {
10
}
} else {
10
};
ric_sender.unbounded_send(time_remaining).unwrap()
}));
// execute the polyfill for safari
Function::new_no_args(include_str!("./ricpolyfill.js"))
.call0(&JsValue::NULL)
.unwrap();
let window = web_sys::window().unwrap();
Self {
window,
raf_receiver,
raf_closure,
ric_receiver,
ric_closure,
}
}
/// waits for some idle time and returns a timeout future that expires after the idle time has passed
pub async fn wait_for_idle_time(&mut self) -> TimeoutFuture {
let ric_fn = self.ric_closure.as_ref().dyn_ref::<Function>().unwrap();
let _cb_id: u32 = self.window.request_idle_callback(ric_fn).unwrap();
let deadline = self.ric_receiver.next().await.unwrap();
TimeoutFuture::new(deadline)
}
pub async fn wait_for_raf(&mut self) {
let raf_fn = self.raf_closure.as_ref().dyn_ref::<Function>().unwrap();
let _id: i32 = self.window.request_animation_frame(raf_fn).unwrap();
self.raf_receiver.next().await.unwrap();
}
}

View file

@ -1,28 +0,0 @@
const requestIdleCallback =
(typeof self !== 'undefined' &&
self.requestIdleCallback &&
self.requestIdleCallback.bind(window)) ||
function (cb) {
const start = Date.now();
return setTimeout(() => {
cb({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 - (Date.now() - start));
},
});
}, 1);
};
const cancelIdleCallback =
(typeof self !== 'undefined' &&
self.cancelIdleCallback &&
self.cancelIdleCallback.bind(window)) ||
function (id) {
return clearTimeout(id);
};
if (typeof window !== 'undefined') {
window.requestIdleCallback = requestIdleCallback;
window.cancelIdleCallback = cancelIdleCallback;
}

View file

@ -1,56 +0,0 @@
use dioxus::prelude::*;
use dioxus_web::Config;
use wasm_bindgen_test::wasm_bindgen_test;
use web_sys::window;
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn makes_tree() {
fn app() -> Element {
rsx! {
div {
div { h1 {} }
div { h2 {} }
}
}
}
let mut dom = VirtualDom::new(app);
let muts = dom.rebuild_to_vec();
dbg!(muts.edits);
}
#[wasm_bindgen_test]
fn rehydrates() {
fn app() -> Element {
rsx! {
div {
div { h1 { "h1" } }
div { h2 { "h2" } }
button {
onclick: move |_| {
println!("clicked");
},
"listener test"
}
{false.then(|| rsx! { "hello" })}
}
}
}
let mut dom = VirtualDom::new(app);
dom.rebuild(&mut dioxus_core::NoOpMutations);
let out = dioxus_ssr::render(&dom);
window()
.unwrap()
.document()
.unwrap()
.body()
.unwrap()
.set_inner_html(&format!("<div id='main'>{out}</div>"));
dioxus_web::launch::launch_cfg(app, Config::new().hydrate(true));
}