Fix templates merging in debug mode in macros (#2828)

* Fix templates merging in debug mode in macros

* Fix clippy

* Fix web-sys scroll to deprecated warning
This commit is contained in:
Evan Almloff 2024-08-13 22:18:54 +02:00 committed by GitHub
parent cab573eefd
commit 959ab67624
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 259 additions and 204 deletions

359
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
#![cfg(not(miri))]
use dioxus::prelude::*;
use dioxus_core::{AttributeValue, DynamicNode, NoOpMutations, VComponent, VNode, *};
use std::{any::Any, cfg, collections::HashSet, default::Default, rc::Rc};
use dioxus_core::{AttributeValue, DynamicNode, NoOpMutations, Template, VComponent, VNode, *};
use std::{any::Any, cell::RefCell, cfg, collections::HashSet, default::Default, rc::Rc};
fn random_ns() -> Option<&'static str> {
let namespace = rand::random::<u8>() % 2;
@ -127,13 +127,18 @@ enum DynamicNodeType {
Other,
}
fn create_random_template() -> (Template, Vec<DynamicNodeType>) {
let mut dynamic_node_type = Vec::new();
fn create_random_template(depth: usize) -> (Template, Box<[DynamicNode]>) {
let mut dynamic_node_types = Vec::new();
let mut template_idx = 0;
let mut attr_idx = 0;
let roots = (0..(1 + rand::random::<usize>() % 5))
.map(|_| {
create_random_template_node(&mut dynamic_node_type, &mut template_idx, &mut attr_idx, 0)
create_random_template_node(
&mut dynamic_node_types,
&mut template_idx,
&mut attr_idx,
0,
)
})
.collect::<Vec<_>>();
assert!(!roots.is_empty());
@ -157,10 +162,16 @@ fn create_random_template() -> (Template, Vec<DynamicNodeType>) {
.collect::<Vec<_>>()
.into_boxed_slice(),
);
(
Template { roots, node_paths, attr_paths },
dynamic_node_type,
)
let dynamic_nodes = dynamic_node_types
.iter()
.map(|ty| match ty {
DynamicNodeType::Text => {
DynamicNode::Text(VText::new(format!("{}", rand::random::<usize>())))
}
DynamicNodeType::Other => create_random_dynamic_node(depth + 1),
})
.collect();
(Template { roots, node_paths, attr_paths }, dynamic_nodes)
}
fn create_random_dynamic_node(depth: usize) -> DynamicNode {
@ -223,31 +234,46 @@ struct DepthProps {
}
fn create_random_element(cx: DepthProps) -> Element {
let last_template = use_hook(|| Rc::new(RefCell::new(None)));
if rand::random::<usize>() % 10 == 0 {
needs_update();
}
let range = if cx.root { 2 } else { 3 };
let node = match rand::random::<usize>() % range {
0 | 1 => {
let (template, dynamic_node_types) = create_random_template();
let node = VNode::new(
// Change both the template and the dynamic nodes
0 => {
let (template, dynamic_nodes) = create_random_template(cx.depth + 1);
last_template.replace(Some(template));
VNode::new(
None,
template,
dynamic_node_types
.iter()
.map(|ty| match ty {
DynamicNodeType::Text => {
DynamicNode::Text(VText::new(format!("{}", rand::random::<usize>())))
}
DynamicNodeType::Other => create_random_dynamic_node(cx.depth + 1),
})
.collect(),
dynamic_nodes,
(0..template.attr_paths.len())
.map(|_| Box::new([create_random_dynamic_attr()]) as Box<[Attribute]>)
.collect(),
);
node
)
}
// Change just the dynamic nodes
1 => {
let (template, dynamic_nodes) = match *last_template.borrow() {
Some(template) => (
template,
(0..template.node_paths.len())
.map(|_| create_random_dynamic_node(cx.depth + 1))
.collect(),
),
None => create_random_template(cx.depth + 1),
};
VNode::new(
None,
template,
dynamic_nodes,
(0..template.attr_paths.len())
.map(|_| Box::new([create_random_dynamic_attr()]) as Box<[Attribute]>)
.collect(),
)
}
// Remove the template
_ => VNode::default(),
};
Element::Ok(node)

View file

@ -13,7 +13,7 @@ pub fn apply_changes(dom: &mut VirtualDom, msg: &HotReloadMsg) {
let id = &template.location;
let value = template.template.clone();
if let Some(mut signal) = ctx.get_signal_with_key(id) {
signal.set(value);
signal.set(Some(value));
}
}
});

View file

@ -531,14 +531,16 @@ impl crate::RenderedElementBacking for web_sys::Element {
&self,
behavior: crate::ScrollBehavior,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<()>>>> {
let options = web_sys::ScrollIntoViewOptions::new();
match behavior {
crate::ScrollBehavior::Instant => self.scroll_into_view_with_scroll_into_view_options(
web_sys::ScrollIntoViewOptions::new().behavior(web_sys::ScrollBehavior::Instant),
),
crate::ScrollBehavior::Smooth => self.scroll_into_view_with_scroll_into_view_options(
web_sys::ScrollIntoViewOptions::new().behavior(web_sys::ScrollBehavior::Smooth),
),
crate::ScrollBehavior::Instant => {
options.set_behavior(web_sys::ScrollBehavior::Instant);
}
crate::ScrollBehavior::Smooth => {
options.set_behavior(web_sys::ScrollBehavior::Smooth);
}
}
self.scroll_into_view_with_scroll_into_view_options(&options);
Box::pin(async { Ok(()) })
}

View file

@ -149,10 +149,17 @@ impl ToTokens for TemplateBody {
#[cfg(debug_assertions)]
{
static __ORIGINAL_TEMPLATE: ::std::sync::OnceLock<dioxus_core::internal::HotReloadedTemplate> = ::std::sync::OnceLock::new();
fn __original_template() -> &'static dioxus_core::internal::HotReloadedTemplate {
if __ORIGINAL_TEMPLATE.get().is_none() {
_ = __ORIGINAL_TEMPLATE.set(#hot_reload_mapping);
}
__ORIGINAL_TEMPLATE.get().unwrap()
}
// The key is important here - we're creating a new GlobalSignal each call to this
// But the key is what's keeping it stable
let __template = GlobalSignal::with_key(
|| #hot_reload_mapping,
|| None::<dioxus_core::internal::HotReloadedTemplate>,
{
const PATH: &str = dioxus_core::const_format::str_replace!(file!(), "\\\\", "/");
const NORMAL: &str = dioxus_core::const_format::str_replace!(PATH, '\\', "/");
@ -161,6 +168,13 @@ impl ToTokens for TemplateBody {
);
__template.maybe_with_rt(|__template_read| {
// If the template has not been hot reloaded, we always use the original template
// Templates nested within macros may be merged because they have the same file-line-column-index
// They cannot be hot reloaded, so this prevents incorrect rendering
let __template_read = match __template_read.as_ref() {
Some(__template_read) => __template_read,
None => __original_template(),
};
let mut __dynamic_literal_pool = dioxus_core::internal::DynamicLiteralPool::new(
vec![ #( #dynamic_text.to_string() ),* ],
);