chore: implemented a small runtime optimization for SSR (#7539)

Prior to this change, the compiler would generate a template literal that had many purely static
string variables nested within it. This change collapses these static strings into the surrounding
template literal which should result in (minor) size and performance improvements for the SSR
generated code.

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
pull/8335/head
Cory Virok 2 years ago committed by GitHub
parent fc5f629812
commit 32a94fcfc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,6 +16,7 @@ import Title from './handlers/Title';
import { AppendTarget, CompileOptions } from '../../interfaces';
import { INode } from '../nodes/interfaces';
import { Expression, TemplateLiteral, Identifier } from 'estree';
import { collapse_template_literal } from '../utils/collapse_template_literal';
import { escape_template } from '../utils/stringify';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
@ -106,6 +107,9 @@ export default class Renderer {
this.current = last.current;
}
// Optimize the TemplateLiteral to remove unnecessary nodes
collapse_template_literal(popped.literal);
return popped.literal;
}

@ -0,0 +1,34 @@
import { TemplateLiteral } from 'estree';
import { escape_template } from './stringify';
/**
* Collapse string literals together
*/
export function collapse_template_literal(literal: TemplateLiteral) {
if (!literal.quasis.length) return;
const collapsed_quasis = [];
const collapsed_expressions = [];
let cur_quasi = literal.quasis[0];
// An expression always follows a quasi and vice versa, ending with a quasi
for (let i = 0; i < literal.quasis.length; i++) {
const expr = literal.expressions[i];
const next_quasi = literal.quasis[i + 1];
// If an expression is a simple string literal, combine it with its preceding
// and following quasi
if (next_quasi && expr && expr.type === 'Literal' && typeof expr.value === 'string') {
cur_quasi.value.raw += escape_template(expr.value) + next_quasi.value.raw;
} else {
if (expr) {
collapsed_expressions.push(expr);
}
collapsed_quasis.push(cur_quasi);
cur_quasi = next_quasi;
}
}
literal.quasis = collapsed_quasis;
literal.expressions = collapsed_expressions;
}

@ -0,0 +1,6 @@
export default {
options: {
generate: 'ssr',
dev: true
}
};

@ -0,0 +1,25 @@
/* generated by Svelte vX.Y.Z */
import { add_attribute, create_ssr_component, escape } from "svelte/internal";
const const1 = 1;
const const2 = 'const2';
function foo() {
return '';
}
const Component = create_ssr_component(($$result, $$props, $$bindings, slots) => {
return `
<div class="class1 class2" style="color:red;">-</div>
<div${add_attribute("class", const1, 0)}>-</div>
<div${add_attribute("class", const1, 0)}>-</div>
<div class="${"class1 " + escape('class2', true)}">-</div>
<div class="${"class1 " + escape(const2, true)}">-</div>
<div class="${"class1 " + escape(const2, true)}"${add_attribute("style", foo(), 0)}>-</div>`;
});
export default Component;

@ -0,0 +1,20 @@
<script>
const const1 = 1;
const const2 = 'const2';
function foo() {
return '';
}
</script>
<!-- canonical case - only markup -->
<div class="class1 class2" style="color:red;">-</div>
<!-- various forms of variable syntax -->
<div class="{const1}">-</div>
<div class={const1}>-</div>
<!-- mixed static string + expressions -->
<div class="class1 {'class2'}">-</div>
<div class="class1 {const2}">-</div>
<div class="class1 {const2}" style={foo()}>-</div>

@ -4,14 +4,11 @@
"message": "You are assigning to a const",
"start": {
"line": 3,
"column": 1,
"character": 31
"column": 1
},
"end": {
"line": 3,
"column": 33,
"character": 63
},
"pos": 31
"column": 33
}
}
]

@ -4,14 +4,11 @@
"message": "You are assigning to a const",
"start": {
"line": 3,
"column": 1,
"character": 43
"column": 1
},
"end": {
"line": 3,
"column": 42,
"character": 84
},
"pos": 43
"column": 42
}
}
]
Loading…
Cancel
Save