Skip to content

Commit

Permalink
Binary size wins
Browse files Browse the repository at this point in the history
  • Loading branch information
zakstucke committed Feb 8, 2025
1 parent 287fc47 commit 65a4662
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 152 deletions.
54 changes: 33 additions & 21 deletions leptos/src/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,35 @@ where
use hydration_context::HydrateSharedContext;
use std::sync::Arc;

// use wasm-bindgen-futures to drive the reactive system
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();

#[cfg(debug_assertions)]
{
if !cfg!(feature = "hydrate") && FIRST_CALL.get() {
logging::warn!(
"It seems like you're trying to use Leptos in hydration mode, \
but the `hydrate` feature is not enabled on the `leptos` \
crate. Add `features = [\"hydrate\"]` to your Cargo.toml for \
the crate to work properly.\n\nNote that hydration and \
client-side rendering now use separate functions from \
leptos::mount: you are calling a hydration function."
);
/// Separate static from generic:
fn inner_1() -> Owner {
// use wasm-bindgen-futures to drive the reactive system
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();

#[cfg(debug_assertions)]
{
if !cfg!(feature = "hydrate") && FIRST_CALL.get() {
logging::warn!(
"It seems like you're trying to use Leptos in hydration \
mode, but the `hydrate` feature is not enabled on the \
`leptos` crate. Add `features = [\"hydrate\"]` to your \
Cargo.toml for the crate to work properly.\n\nNote that \
hydration and client-side rendering now use separate \
functions from leptos::mount: you are calling a \
hydration function."
);
}
FIRST_CALL.set(false);
}
FIRST_CALL.set(false);

// create a new reactive owner and use it as the root node to run the app
Owner::new_root(Some(Arc::new(HydrateSharedContext::new())))
}

// create a new reactive owner and use it as the root node to run the app
let owner = Owner::new_root(Some(Arc::new(HydrateSharedContext::new())));
let owner = inner_1();

let mountable = owner.with(move || {
let view = f().into_view();
view.hydrate::<true>(
Expand All @@ -75,10 +82,15 @@ where
)
});

if let Some(sc) = Owner::current_shared_context() {
sc.hydration_complete();
/// Separate static from generic:
fn inner_2() {
if let Some(sc) = Owner::current_shared_context() {
sc.hydration_complete();
}
}

inner_2();

// returns a handle that owns the owner
// when this is dropped, it will clean up the reactive system and unmount the view
UnmountHandle { owner, mountable }
Expand Down
22 changes: 6 additions & 16 deletions meta/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,9 @@ where

fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
let el = document().body().expect("there to be a <body> element");
let attributes = self.attributes.build(&el);
let extra_attrs = extra_attrs.map(|attrs| attrs.build(&el));
BodyViewState {
attributes,
extra_attrs,
attributes: self.attributes.build(&el),
extra_attrs: extra_attrs.build(&el),
}
}

Expand All @@ -86,11 +84,7 @@ where
extra_attrs: Option<Vec<AnyAttribute>>,
) {
self.attributes.rebuild(&mut state.attributes);
if let (Some(extra_attrs), Some(extra_attr_states)) =
(extra_attrs, &mut state.extra_attrs)
{
extra_attrs.rebuild(extra_attr_states);
}
extra_attrs.rebuild(&mut state.extra_attrs);
}
}

Expand Down Expand Up @@ -125,7 +119,7 @@ where

fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
self.attributes.dry_resolve();
extra_attrs.iter_mut().for_each(Attribute::dry_resolve);
ExtraAttrsMut::dry_resolve(&mut extra_attrs)
}

async fn resolve(
Expand Down Expand Up @@ -167,13 +161,9 @@ where
extra_attrs: Option<Vec<AnyAttribute>>,
) -> Self::State {
let el = document().body().expect("there to be a <body> element");
let attributes = self.attributes.hydrate::<FROM_SERVER>(&el);
let extra_attrs =
extra_attrs.map(|attrs| attrs.hydrate::<FROM_SERVER>(&el));

BodyViewState {
attributes,
extra_attrs,
attributes: self.attributes.hydrate::<FROM_SERVER>(&el),
extra_attrs: extra_attrs.hydrate::<FROM_SERVER>(&el),
}
}

Expand Down
29 changes: 6 additions & 23 deletions meta/src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,9 @@ where
.document_element()
.expect("there to be a <html> element");

let attributes = self.attributes.build(&el);
let extra_attrs = extra_attrs.map(|attrs| {
attrs.into_iter().map(|attr| attr.build(&el)).collect()
});

HtmlViewState {
attributes,
extra_attrs,
attributes: self.attributes.build(&el),
extra_attrs: extra_attrs.build(&el),
}
}

Expand All @@ -89,11 +84,7 @@ where
extra_attrs: Option<Vec<AnyAttribute>>,
) {
self.attributes.rebuild(&mut state.attributes);
if let (Some(extra_attrs), Some(extra_attr_states)) =
(extra_attrs, &mut state.extra_attrs)
{
extra_attrs.rebuild(extra_attr_states);
}
extra_attrs.rebuild(&mut state.extra_attrs);
}
}

Expand Down Expand Up @@ -128,7 +119,7 @@ where

fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
self.attributes.dry_resolve();
extra_attrs.iter_mut().for_each(Attribute::dry_resolve);
extra_attrs.dry_resolve();
}

async fn resolve(
Expand Down Expand Up @@ -173,17 +164,9 @@ where
.document_element()
.expect("there to be a <html> element");

let attributes = self.attributes.hydrate::<FROM_SERVER>(&el);
let extra_attrs = extra_attrs.map(|attrs| {
attrs
.into_iter()
.map(|attr| attr.hydrate::<FROM_SERVER>(&el))
.collect()
});

HtmlViewState {
attributes,
extra_attrs,
attributes: self.attributes.hydrate::<FROM_SERVER>(&el),
extra_attrs: extra_attrs.hydrate::<FROM_SERVER>(&el),
}
}

Expand Down
103 changes: 51 additions & 52 deletions reactive_graph/src/effect/render_effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,65 +54,15 @@ where
{
/// Creates a new render effect, which immediately runs `fun`.
pub fn new(fun: impl FnMut(Option<T>) -> T + 'static) -> Self {
Self::new_with_value(fun, None)
Self::new_with_value_erased(Box::new(fun), None)
}

/// Creates a new render effect with an initial value.
pub fn new_with_value(
fun: impl FnMut(Option<T>) -> T + 'static,
initial_value: Option<T>,
) -> Self {
fn erased<T>(
mut fun: Box<dyn FnMut(Option<T>) -> T + 'static>,
initial_value: Option<T>,
) -> RenderEffect<T> {
let (observer, mut rx) = channel();
let value = Arc::new(RwLock::new(None::<T>));
let owner = Owner::new();
let inner = Arc::new(RwLock::new(EffectInner {
dirty: false,
observer,
sources: SourceSet::new(),
}));

let initial_value = cfg!(feature = "effects").then(|| {
owner.with(|| {
inner
.to_any_subscriber()
.with_observer(|| fun(initial_value))
})
});
*value.write().or_poisoned() = initial_value;

if cfg!(feature = "effects") {
Executor::spawn_local({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();

async move {
while rx.next().await.is_some() {
if subscriber.with_observer(|| {
subscriber.update_if_necessary()
}) {
subscriber.clear_sources(&subscriber);

let old_value = mem::take(
&mut *value.write().or_poisoned(),
);
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
}
}
});
}

RenderEffect { value, inner }
}

erased(Box::new(fun), initial_value)
Self::new_with_value_erased(Box::new(fun), initial_value)
}

/// Mutably accesses the current value.
Expand All @@ -127,6 +77,55 @@ where
pub fn take_value(&self) -> Option<T> {
self.value.write().or_poisoned().take()
}

fn new_with_value_erased(
mut fun: Box<dyn FnMut(Option<T>) -> T + 'static>,
initial_value: Option<T>,
) -> Self {
let (observer, mut rx) = channel();
let value = Arc::new(RwLock::new(None::<T>));
let owner = Owner::new();
let inner = Arc::new(RwLock::new(EffectInner {
dirty: false,
observer,
sources: SourceSet::new(),
}));

let initial_value = cfg!(feature = "effects").then(|| {
owner.with(|| {
inner
.to_any_subscriber()
.with_observer(|| fun(initial_value))
})
});
*value.write().or_poisoned() = initial_value;

if cfg!(feature = "effects") {
Executor::spawn_local({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();

async move {
while rx.next().await.is_some() {
if subscriber
.with_observer(|| subscriber.update_if_necessary())
{
subscriber.clear_sources(&subscriber);

let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
}
}
});
}

RenderEffect { value, inner }
}
}

impl<T> RenderEffect<T>
Expand Down
7 changes: 7 additions & 0 deletions tachys/src/html/attribute/any_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ impl Attribute for AnyAttribute {
}
}

/// Helper to summate html len over extra attrs, separated from generic code.
pub fn extra_attrs_html_len(extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
extra_attrs
.map(|attrs| attrs.into_iter().map(Attribute::html_len).sum::<usize>())
.unwrap_or(0)
}

impl NextAttribute for Vec<AnyAttribute> {
type Output<NewAttr: Attribute> = Self;

Expand Down
Loading

0 comments on commit 65a4662

Please sign in to comment.