Merge branch 'upstream' into fix-ssr-raw-attributes

This commit is contained in:
Evan Almloff committed 2023-04-12 09:11:25 -05:00
commit 6afd764aa4
109 files changed
+6361 -4894

No files matched your search

+52 -3
View File
@@ -17,6 +17,14 @@ pub enum Segment {
Attr(usize),
Node(usize),
PreRendered(String),
/// A marker for where to insert a dynamic styles
StyleMarker {
// If the marker is inside a style tag or not
// This will be true if there are static styles
inside_style_tag: bool,
},
/// A marker for where to insert a dynamic inner html
InnerHtmlMarker,
}
impl std::fmt::Write for StringChain {
@@ -61,20 +69,61 @@ impl StringCache {
} => {
cur_path.push(root_idx);
write!(chain, "<{tag}")?;
// we need to collect the styles and write them at the end
let mut styles = Vec::new();
// we need to collect the inner html and write it at the end
let mut inner_html = None;
// we need to keep track of if we have dynamic attrs to know if we need to insert a style and inner_html marker
let mut has_dynamic_attrs = false;
for attr in *attrs {
match attr {
TemplateAttribute::Static { name, value, .. } => {
write!(chain, " {name}=\"{value}\"")?;
TemplateAttribute::Static {
name,
value,
namespace,
} => {
if *name == "dangerous_inner_html" {
inner_html = Some(value);
} else if let Some("style") = namespace {
styles.push((name, value));
} else {
write!(chain, " {name}=\"{value}\"")?;
}
}
TemplateAttribute::Dynamic { id: index } => {
chain.segments.push(Segment::Attr(*index))
chain.segments.push(Segment::Attr(*index));
has_dynamic_attrs = true;
}
}
}
// write the styles
if !styles.is_empty() {
write!(chain, " style=\"")?;
for (name, value) in styles {
write!(chain, "{name}:{value};")?;
}
chain.segments.push(Segment::StyleMarker {
inside_style_tag: true,
});
write!(chain, "\"")?;
} else if has_dynamic_attrs {
chain.segments.push(Segment::StyleMarker {
inside_style_tag: false,
});
}
if children.is_empty() && tag_is_self_closing(tag) {
write!(chain, "/>")?;
} else {
write!(chain, ">")?;
// Write the static inner html, or insert a marker if dynamic inner html is possible
if let Some(inner_html) = inner_html {
chain.write_str(inner_html)?;
} else if has_dynamic_attrs {
chain.segments.push(Segment::InnerHtmlMarker);
}
for child in *children {
Self::recurse(child, cur_path, root_idx, chain)?;
}
+69 -8
View File
@@ -70,17 +70,32 @@ impl Renderer {
.or_insert_with(|| Rc::new(StringCache::from_template(template).unwrap()))
.clone();
let mut inner_html = None;
// We need to keep track of the dynamic styles so we can insert them into the right place
let mut accumulated_dynamic_styles = Vec::new();
for segment in entry.segments.iter() {
match segment {
Segment::Attr(idx) => {
let attr = &template.dynamic_attrs[*idx];
match attr.value {
AttributeValue::Text(value) => write!(buf, " {}=\"{}\"", attr.name, value)?,
AttributeValue::Bool(value) => write!(buf, " {}={}", attr.name, value)?,
AttributeValue::Int(value) => write!(buf, " {}={}", attr.name, value)?,
AttributeValue::Float(value) => write!(buf, " {}={}", attr.name, value)?,
_ => {}
};
if attr.name == "dangerous_inner_html" {
inner_html = Some(attr);
} else if attr.namespace == Some("style") {
accumulated_dynamic_styles.push(attr);
} else {
match attr.value {
AttributeValue::Text(value) => {
write!(buf, " {}=\"{}\"", attr.name, value)?
}
AttributeValue::Bool(value) => write!(buf, " {}={}", attr.name, value)?,
AttributeValue::Int(value) => write!(buf, " {}={}", attr.name, value)?,
AttributeValue::Float(value) => {
write!(buf, " {}={}", attr.name, value)?
}
_ => {}
};
}
}
Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
DynamicNode::Component(node) => {
@@ -130,6 +145,47 @@ impl Renderer {
},
Segment::PreRendered(contents) => write!(buf, "{contents}")?,
Segment::StyleMarker { inside_style_tag } => {
if !accumulated_dynamic_styles.is_empty() {
// if we are inside a style tag, we don't need to write the style attribute
if !*inside_style_tag {
write!(buf, " style=\"")?;
}
for attr in &accumulated_dynamic_styles {
match attr.value {
AttributeValue::Text(value) => {
write!(buf, "{}:{};", attr.name, value)?
}
AttributeValue::Bool(value) => {
write!(buf, "{}:{};", attr.name, value)?
}
AttributeValue::Float(f) => write!(buf, "{}:{};", attr.name, f)?,
AttributeValue::Int(i) => write!(buf, "{}:{};", attr.name, i)?,
_ => {}
};
}
if !*inside_style_tag {
write!(buf, "\"")?;
}
// clear the accumulated styles
accumulated_dynamic_styles.clear();
}
}
Segment::InnerHtmlMarker => {
if let Some(inner_html) = inner_html.take() {
let inner_html = &inner_html.value;
match inner_html {
AttributeValue::Text(value) => write!(buf, "{}", value)?,
AttributeValue::Bool(value) => write!(buf, "{}", value)?,
AttributeValue::Float(f) => write!(buf, "{}", f)?,
AttributeValue::Int(i) => write!(buf, "{}", i)?,
_ => {}
}
}
}
}
}
@@ -170,7 +226,12 @@ fn to_string_works() {
vec![
PreRendered("<div class=\"asdasdasd\" class=\"asdasdasd\"".into(),),
Attr(0,),
PreRendered(">Hello world 1 --&gt;".into(),),
StyleMarker {
inside_style_tag: false,
},
PreRendered(">".into()),
InnerHtmlMarker,
PreRendered("Hello world 1 --&gt;".into(),),
Node(0,),
PreRendered(
"&lt;-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div>".into(),