Skip to content

Commit c1c74ea

Browse files
committed
Get view-macro SSR optimization working
1 parent b54a602 commit c1c74ea

File tree

3 files changed

+70
-33
lines changed

3 files changed

+70
-33
lines changed

leptos_dom/src/ssr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,8 @@ fn to_kebab_case(name: &str) -> String {
415415

416416
new_name
417417
}
418+
419+
#[doc(hidden)]
420+
pub fn escape_attr<T>(value: &T) -> Cow<'_, str> where T: AsRef<str>{
421+
html_escape::encode_double_quoted_attribute(value)
422+
}

leptos_macro/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,7 @@ pub fn view(tokens: TokenStream) -> TokenStream {
251251
Ok(nodes) => render_view(
252252
&proc_macro2::Ident::new(&cx.to_string(), cx.span().into()),
253253
&nodes,
254-
// swap to Mode::default() to use faster SSR templating
255-
Mode::Client, //Mode::default(),
254+
Mode::default(),
256255
),
257256
Err(error) => error.to_compile_error(),
258257
}

leptos_macro/src/view.rs

+64-31
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ fn root_node_to_tokens_ssr(cx: &Ident, node: &Node) -> TokenStream {
181181
Node::Block(node) => {
182182
let value = node.value.as_ref();
183183
quote! {
184+
#[allow(unused_braces)]
184185
#value
185186
}
186187
}
@@ -205,32 +206,43 @@ fn fragment_to_tokens_ssr(cx: &Ident, _span: Span, nodes: &[Node]) -> TokenStrea
205206
}
206207

207208
fn root_element_to_tokens_ssr(cx: &Ident, node: &NodeElement) -> TokenStream {
208-
let mut template = String::new();
209-
let mut holes = Vec::<TokenStream>::new();
210-
let mut exprs_for_compiler = Vec::<TokenStream>::new();
209+
if is_component_node(&node) {
210+
component_to_tokens(cx, node)
211+
} else {
212+
let mut template = String::new();
213+
let mut holes = Vec::<TokenStream>::new();
214+
let mut exprs_for_compiler = Vec::<TokenStream>::new();
211215

212-
element_to_tokens_ssr(cx, node, &mut template, &mut holes, &mut exprs_for_compiler);
216+
element_to_tokens_ssr(
217+
cx,
218+
node,
219+
&mut template,
220+
&mut holes,
221+
&mut exprs_for_compiler,
222+
true,
223+
);
224+
225+
let template = if holes.is_empty() {
226+
quote! {
227+
#template
228+
}
229+
} else {
230+
quote! {
231+
format!(
232+
#template,
233+
#(#holes)*
234+
)
235+
}
236+
};
213237

214-
let template = if holes.is_empty() {
238+
let tag_name = node.name.to_string();
239+
let typed_element_name = Ident::new(&camel_case_tag_name(&tag_name), node.name.span());
215240
quote! {
216-
#template
241+
{
242+
#(#exprs_for_compiler)*
243+
::leptos::HtmlElement::from_html(cx, leptos::#typed_element_name::default(), #template)
217244
}
218-
} else {
219-
quote! {
220-
format!(
221-
#template,
222-
#(#holes)*
223-
)
224245
}
225-
};
226-
227-
let tag_name = node.name.to_string();
228-
let typed_element_name = Ident::new(&camel_case_tag_name(&tag_name), node.name.span());
229-
quote! {
230-
{
231-
#(#exprs_for_compiler)*
232-
::leptos::HtmlElement::from_html(cx, leptos::#typed_element_name::default(), #template)
233-
}
234246
}
235247
}
236248

@@ -240,6 +252,7 @@ fn element_to_tokens_ssr(
240252
template: &mut String,
241253
holes: &mut Vec<TokenStream>,
242254
exprs_for_compiler: &mut Vec<TokenStream>,
255+
is_root: bool,
243256
) {
244257
if is_component_node(node) {
245258
template.push_str("{}");
@@ -257,6 +270,26 @@ fn element_to_tokens_ssr(
257270
}
258271
}
259272

273+
// insert hydration ID
274+
let hydration_id = if is_root {
275+
quote! { leptos::HydrationCtx::peek(), }
276+
} else {
277+
quote! { leptos::HydrationCtx::id(), }
278+
};
279+
match node
280+
.attributes
281+
.iter()
282+
.find(|node| matches!(node, Node::Attribute(attr) if attr.key.to_string() == "id"))
283+
{
284+
Some(_) => {
285+
template.push_str(&format!(" leptos-hk=\"_{{}}\""));
286+
}
287+
None => {
288+
template.push_str(&format!(" id=\"_{{}}\""));
289+
}
290+
}
291+
holes.push(hydration_id);
292+
260293
set_class_attribute_ssr(cx, node, template, holes);
261294

262295
if is_self_closing(node) {
@@ -266,7 +299,7 @@ fn element_to_tokens_ssr(
266299
for child in &node.children {
267300
match child {
268301
Node::Element(child) => {
269-
element_to_tokens_ssr(cx, child, template, holes, exprs_for_compiler)
302+
element_to_tokens_ssr(cx, child, template, holes, exprs_for_compiler, false)
270303
}
271304
Node::Text(text) => {
272305
if let Some(value) = value_to_string(&text.value) {
@@ -345,13 +378,12 @@ fn attribute_to_tokens_ssr(
345378
.parse::<TokenStream>()
346379
.expect("couldn't parse event name");
347380

381+
let event_type = if is_force_undelegated {
382+
quote! { ::leptos::ev::undelegated(::leptos::ev::#event_type) }
383+
} else {
384+
quote! { ::leptos::ev::#event_type }
385+
};
348386
exprs_for_compiler.push(quote! {
349-
let event_type = if is_force_undelegated {
350-
quote! { ::leptos::ev::undelegated(::leptos::ev::#event_type) }
351-
} else {
352-
quote! { ::leptos::ev::#event_type }
353-
};
354-
355387
leptos::ssr_event_listener(#event_type, #handler);
356388
})
357389
} else if name.strip_prefix("prop:").is_some() || name.strip_prefix("class:").is_some() {
@@ -366,15 +398,16 @@ fn attribute_to_tokens_ssr(
366398

367399
if let Some(value) = node.value.as_ref() {
368400
if let Some(value) = value_to_string(value) {
401+
template.push_str("=\"");
369402
template.push_str(&value);
403+
template.push('"');
370404
} else {
371-
template.push_str("{}");
405+
template.push_str("=\"{}\"");
372406
let value = value.as_ref();
373407
holes.push(quote! {
374-
leptos::escape_attr(&{#value}.into_attribute(#cx).as_value_string(#name)),
408+
leptos::escape_attr(&{#value}.into_attribute(#cx).as_nameless_value_string()),
375409
})
376410
}
377-
template.push('"');
378411
}
379412
}
380413
}

0 commit comments

Comments
 (0)