optimizations for wasm size (#582)

* optimize for size

* fix tests

* revert log feature

* make backtrace not optional

* remove dev feature from web dev-deps
This commit is contained in:
Demonthos authored and GitHub committed 2022-11-16 22:22:13 -08:00
1 parent 8ea61e1b3e
commit f21c8423eb
6 files changed
+61 -28

No files matched your search

+42 -12
View File
@@ -2,13 +2,13 @@
//!
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
use std::{collections::VecDeque, iter::FromIterator, task::Poll};
use crate::diff::DiffState;
use crate::innerlude::*;
use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
use futures_util::{future::poll_fn, StreamExt};
use indexmap::IndexSet;
use rustc_hash::FxHashSet;
use std::{collections::VecDeque, iter::FromIterator, task::Poll};
/// A virtual node system that progresses user events and diffs UI trees.
///
@@ -107,7 +107,8 @@ pub struct VirtualDom {
scopes: ScopeArena,
pending_messages: VecDeque<SchedulerMsg>,
dirty_scopes: IndexSet<ScopeId>,
dirty_scopes: Vec<ScopeId>,
removed_scopes: FxHashSet<ScopeId>,
channel: (
UnboundedSender<SchedulerMsg>,
@@ -238,8 +239,9 @@ impl VirtualDom {
root: ElementId(0),
scopes,
channel,
dirty_scopes: IndexSet::from_iter([ScopeId(0)]),
dirty_scopes: Vec::from_iter([ScopeId(0)]),
pending_messages: VecDeque::new(),
removed_scopes: FxHashSet::default(),
}
}
@@ -396,11 +398,18 @@ impl VirtualDom {
}
}
SchedulerMsg::Immediate(s) => {
self.dirty_scopes.insert(s);
self.mark_dirty_scope(s);
}
SchedulerMsg::DirtyAll => {
for id in self.scopes.scopes.borrow().keys() {
self.dirty_scopes.insert(*id);
let dirty = self
.scopes
.scopes
.borrow()
.keys()
.copied()
.collect::<Vec<_>>();
for id in dirty {
self.mark_dirty_scope(id);
}
}
#[cfg(any(feature = "hot-reload", debug_assertions))]
@@ -474,6 +483,7 @@ impl VirtualDom {
pub fn work_with_deadline(&mut self, mut deadline: impl FnMut() -> bool) -> Vec<Mutations> {
let mut committed_mutations = vec![];
self.scopes.template_bump.reset();
self.removed_scopes.clear();
while !self.dirty_scopes.is_empty() {
let scopes = &self.scopes;
@@ -492,7 +502,10 @@ impl VirtualDom {
});
if let Some(scopeid) = self.dirty_scopes.pop() {
if !ran_scopes.contains(&scopeid) {
if scopes.get_scope(scopeid).is_some()
&& !self.removed_scopes.contains(&scopeid)
&& !ran_scopes.contains(&scopeid)
{
ran_scopes.insert(scopeid);
self.scopes.run_scope(scopeid);
@@ -501,9 +514,8 @@ impl VirtualDom {
let DiffState { mutations, .. } = diff_state;
for scope in &mutations.dirty_scopes {
self.dirty_scopes.remove(scope);
}
self.removed_scopes
.extend(mutations.dirty_scopes.iter().copied());
if !mutations.edits.is_empty() {
committed_mutations.push(mutations);
@@ -729,6 +741,23 @@ impl VirtualDom {
})
.unwrap()
}
fn mark_dirty_scope(&mut self, scope_id: ScopeId) {
let scopes = &self.scopes;
if let Some(scope) = scopes.get_scope(scope_id) {
let height = scope.height;
let id = scope_id.0;
if let Err(index) = self.dirty_scopes.binary_search_by(|new| {
let scope = scopes.get_scope(*new).unwrap();
let new_height = scope.height;
let new_id = &scope.scope_id();
height.cmp(&new_height).then(new_id.0.cmp(&id))
}) {
self.dirty_scopes.insert(index, scope_id);
log::info!("mark_dirty_scope: {:?}", self.dirty_scopes);
}
}
}
}
/*
@@ -736,7 +765,8 @@ Scopes and ScopeArenas are never dropped internally.
An app will always occupy as much memory as its biggest form.
This means we need to handle all specifics of drop *here*. It's easier
to reason about centralizing all the drop logic in one spot rather than scattered in each module.
to reason about centralizing all the drop
logic in one spot rather than scattered in each module.
Broadly speaking, we want to use the remove_nodes method to clean up *everything*
This will drop listeners, borrowed props, and hooks for all components.