Skip to content

Commit 55d5d08

Browse files
committed
Omit conditional elements without an else branch when present in children
1 parent 2c4ea60 commit 55d5d08

File tree

3 files changed

+129
-9
lines changed

3 files changed

+129
-9
lines changed

packages/yew-macro/src/html_tree/html_if.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use boolinator::Boolinator;
22
use proc_macro2::TokenStream;
3-
use quote::{quote_spanned, ToTokens};
3+
use quote::{quote, quote_spanned, ToTokens};
44
use syn::buffer::Cursor;
55
use syn::parse::{Parse, ParseStream};
66
use syn::spanned::Spanned;
@@ -139,3 +139,32 @@ impl ToTokens for HtmlRootBracedOrIf {
139139
}
140140
}
141141
}
142+
143+
pub struct HtmlIfIterItem<'a>(pub &'a HtmlIf);
144+
145+
impl<'a> ToNodeIterator for HtmlIfIterItem<'a> {
146+
fn to_node_iterator_stream(&self) -> Option<TokenStream> {
147+
let HtmlIf {
148+
if_token,
149+
cond,
150+
then_branch,
151+
else_branch,
152+
..
153+
} = &self.0;
154+
155+
if else_branch.is_none() {
156+
let new_tokens = quote_spanned! {if_token.span()=>
157+
if #cond {
158+
Some(::std::convert::Into::into(#then_branch))
159+
} else {
160+
None
161+
}
162+
};
163+
164+
Some(new_tokens)
165+
} else {
166+
let new_tokens = self.0.to_node_iterator_stream().unwrap();
167+
Some(quote! { Some(#new_tokens) })
168+
}
169+
}
170+
}

packages/yew-macro/src/html_tree/mod.rs

+41-8
Original file line numberDiff line numberDiff line change
@@ -241,23 +241,56 @@ impl HtmlChildrenTree {
241241
if self.only_single_node_children() {
242242
// optimize for the common case where all children are single nodes (only using literal
243243
// html).
244-
let children_into = children
245-
.iter()
246-
.map(|child| quote_spanned! {child.span()=> ::std::convert::Into::into(#child) });
244+
let children_into = children.iter().map(|child| {
245+
if let HtmlTree::If(if_clause) = child {
246+
html_if::HtmlIfIterItem(&**if_clause)
247+
.to_node_iterator_stream()
248+
.unwrap()
249+
} else {
250+
quote_spanned! {child.span()=> Some(::std::convert::Into::into(#child)) }
251+
}
252+
});
253+
247254
return quote! {
248-
::std::vec![#(#children_into),*]
255+
::std::vec![#(#children_into),*].into_iter().filter_map(|x| x).collect::<Vec<_>>()
249256
};
250257
}
251258

252259
let vec_ident = Ident::new("__yew_v", Span::mixed_site());
253260
let add_children_streams = children.iter().map(|child| {
254261
if let Some(node_iterator_stream) = child.to_node_iterator_stream() {
255-
quote! {
256-
::std::iter::Extend::extend(&mut #vec_ident, #node_iterator_stream);
262+
if let HtmlTree::If(if_clause) = child {
263+
let tokens = html_if::HtmlIfIterItem(&**if_clause)
264+
.to_node_iterator_stream()
265+
.unwrap();
266+
267+
quote! {
268+
if let Some(iter) = #tokens {
269+
::std::iter::Extend::extend(&mut #vec_ident, iter)
270+
} else {
271+
#vec_ident
272+
}
273+
}
274+
} else {
275+
quote! {
276+
::std::iter::Extend::extend(&mut #vec_ident, #node_iterator_stream);
277+
}
257278
}
258279
} else {
259-
quote_spanned! {child.span()=>
260-
#vec_ident.push(::std::convert::Into::into(#child));
280+
if let HtmlTree::If(if_clause) = child {
281+
let tokens = html_if::HtmlIfIterItem(&**if_clause)
282+
.to_node_iterator_stream()
283+
.unwrap();
284+
285+
quote! {child.span()=>
286+
if let Some(iter) = #tokens {
287+
#vec_ident.push(iter)
288+
}
289+
}
290+
} else {
291+
quote_spanned! {child.span()=>
292+
#vec_ident.push(::std::convert::Into::into(#child));
293+
}
261294
}
262295
}
263296
});

packages/yew/tests/children.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#![cfg(not(target_arch = "wasm32"))]
2+
3+
use yew::prelude::*;
4+
5+
#[tokio::test]
6+
async fn conditional_children_are_omitted() {
7+
#[derive(Properties, PartialEq)]
8+
pub struct Props {
9+
#[prop_or_default]
10+
pub children: Children,
11+
}
12+
13+
#[function_component]
14+
pub fn Problem(p: &Props) -> Html {
15+
html! {
16+
<div class="container">
17+
{
18+
for p.children.iter().enumerate().map(|(i, x)| {
19+
html! {
20+
<div>
21+
<span>{x}</span>
22+
<span>{i}</span>
23+
</div>
24+
}
25+
})
26+
}
27+
</div>
28+
}
29+
}
30+
31+
#[function_component]
32+
fn App() -> Html {
33+
let b = false;
34+
html! {
35+
<Problem>
36+
<span>{ "A" }</span>
37+
<span>{ "B" }</span>
38+
if b {
39+
<span>{ "C" }</span>
40+
}
41+
<span>{ "D" }</span>
42+
</Problem>
43+
}
44+
}
45+
46+
let mut s = String::new();
47+
yew::ServerRenderer::<App>::new()
48+
.render_to_string(&mut s)
49+
.await;
50+
51+
assert_eq!(
52+
s,
53+
"<!--<[children::App]>--><!--<[children::Problem]>--><div \
54+
class=\"container\"><div><span><span>A</span></span><span>0</span></\
55+
div><div><span><span>B</span></span><span>1</span></div><div><span><span>D</span></\
56+
span><span>2</span></div></div><!--</[children::Problem]>--><!--</[children::App]>-->"
57+
);
58+
}

0 commit comments

Comments
 (0)