Switch to a pool of dynamic values for hot reloading (#2705)
* create the dynamic value pool * assign ids to dynamic formatted segments * separate the rendering and literal pools * rsx output compiles again * more examples compiling with new rsx expansion * update template body explanation * all workspace examples compile * fix formatted segments in keys * start hot reload diffing * fix component literal hot reloading * start integrate new hot reloading with the CLI * simple hot reloads working * Fix hot reloading blocks with components * implement hot reloading for if chains * Fix hot reloading after a template requires a full rebuild * Fix hot reloading any attribute values * remove unsafe from hot reload utils * Fix hot reloading empty rsx * add more hot reloading tests * reorganize hot reload module * fix web hydration * fix empty rsx nodes in autoformatting * fix tests * remove path sorting logic from core * make template names more consistent in debug mode * fix quote_as_hot_reload_literal for explicitly typed literals * fix can_be_shorthand for string literals * fix formatted single dynamic expression * Fix usize component properties and playwright tests * remove default implementation for TemplateBody * add a bunch more comments for diffing, scoring and why this scoring system is optimal
This commit is contained in:
1 parent
f3ca1484a1
commit
34bdcd15cf
40 files changed
+2288
-1897
No files matched your search
@@ -1,6 +1,3 @@
|
||||
#[cfg(feature = "hot_reload")]
|
||||
use dioxus_core::internal::{FmtSegment, FmtedSegments};
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
@@ -94,64 +91,6 @@ impl IfmtInput {
|
||||
map
|
||||
}
|
||||
|
||||
#[cfg(feature = "hot_reload")]
|
||||
pub fn fmt_segments(old: &Self, new: &Self) -> Option<FmtedSegments> {
|
||||
use crate::intern;
|
||||
|
||||
// Make sure all the dynamic segments of b show up in a
|
||||
for segment in new.segments.iter() {
|
||||
if segment.is_formatted() && !old.segments.contains(segment) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all the formatted segments from the original
|
||||
let mut out = vec![];
|
||||
|
||||
// the original list of formatted segments
|
||||
let mut fmted = old
|
||||
.segments
|
||||
.iter()
|
||||
.flat_map(|f| match f {
|
||||
crate::Segment::Literal(_) => None,
|
||||
crate::Segment::Formatted(f) => Some(f),
|
||||
})
|
||||
.cloned()
|
||||
.map(Some)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for segment in new.segments.iter() {
|
||||
match segment {
|
||||
crate::Segment::Literal(lit) => {
|
||||
// create a &'static str by leaking the string
|
||||
let lit = intern(lit.clone().into_boxed_str());
|
||||
out.push(FmtSegment::Literal { value: lit });
|
||||
}
|
||||
crate::Segment::Formatted(fmt) => {
|
||||
// Find the formatted segment in the original
|
||||
// Set it to None when we find it so we don't re-render it on accident
|
||||
let idx = fmted
|
||||
.iter_mut()
|
||||
.position(|_s| {
|
||||
if let Some(s) = _s {
|
||||
if s == fmt {
|
||||
*_s = None;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
out.push(FmtSegment::Dynamic { id: idx });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(FmtedSegments::new(out))
|
||||
}
|
||||
|
||||
fn is_simple_expr(&self) -> bool {
|
||||
self.segments.iter().all(|seg| match seg {
|
||||
Segment::Literal(_) => true,
|
||||
@@ -272,6 +211,11 @@ impl IfmtInput {
|
||||
|
||||
impl ToTokens for IfmtInput {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// If the input is a string literal, we can just return it
|
||||
if let Some(static_str) = self.to_static() {
|
||||
return static_str.to_tokens(tokens);
|
||||
}
|
||||
|
||||
// Try to turn it into a single _.to_string() call
|
||||
if !cfg!(debug_assertions) {
|
||||
if let Some(single_dynamic) = self.try_to_string() {
|
||||
@@ -284,7 +228,7 @@ impl ToTokens for IfmtInput {
|
||||
if self.is_simple_expr() {
|
||||
let raw = &self.source;
|
||||
tokens.extend(quote! {
|
||||
::std::format_args!(#raw)
|
||||
::std::format!(#raw)
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -323,7 +267,7 @@ impl ToTokens for IfmtInput {
|
||||
|
||||
quote_spanned! {
|
||||
span =>
|
||||
::std::format_args!(
|
||||
::std::format!(
|
||||
#format_literal
|
||||
#(, #positional_args)*
|
||||
)
|
||||
@@ -359,7 +303,7 @@ impl ToTokens for FormattedSegment {
|
||||
let (fmt, seg) = (&self.format_args, &self.segment);
|
||||
let fmt = format!("{{0:{fmt}}}");
|
||||
tokens.append_all(quote! {
|
||||
format_args!(#fmt, #seg)
|
||||
format!(#fmt, #seg)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -470,11 +414,4 @@ mod tests {
|
||||
println!("{}", input.to_string_with_quotes());
|
||||
assert!(input.is_static());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fmt_segments() {
|
||||
let left = syn::parse2::<IfmtInput>(quote! { "thing {abc}" }).unwrap();
|
||||
let right = syn::parse2::<IfmtInput>(quote! { "thing" }).unwrap();
|
||||
let _segments = IfmtInput::fmt_segments(&left, &right).unwrap();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user