Skip to content

Commit e7a2350

Browse files
Rich-HarrisConduitrybenmccann
authored
Faster SSR (#5701)
Co-authored-by: Conduitry <[email protected]> Co-authored-by: Ben McCann <[email protected]>
1 parent 34eb6ef commit e7a2350

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

src/compiler/compile/render_ssr/handlers/shared/get_attribute_value.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function get_class_attribute_value(attribute: Attribute): ESTreeExpressio
99
// handle special case — `class={possiblyUndefined}` with scoped CSS
1010
if (attribute.chunks.length === 2 && (attribute.chunks[1] as Text).synthetic) {
1111
const value = (attribute.chunks[0] as Expression).node;
12-
return x`@escape(@null_to_empty(${value})) + "${(attribute.chunks[1] as Text).data}"`;
12+
return x`@escape(@null_to_empty(${value}), true) + "${(attribute.chunks[1] as Text).data}"`;
1313
}
1414

1515
return get_attribute_value(attribute);
@@ -22,7 +22,7 @@ export function get_attribute_value(attribute: Attribute): ESTreeExpression {
2222
.map((chunk) => {
2323
return chunk.type === 'Text'
2424
? string_literal(chunk.data.replace(/"/g, '&quot;')) as ESTreeExpression
25-
: x`@escape(${chunk.node})`;
25+
: x`@escape(${chunk.node}, true)`;
2626
})
2727
.reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
2828
}

src/runtime/internal/ssr.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,34 @@ export function merge_ssr_styles(style_attribute, style_directive) {
6969
return style_object;
7070
}
7171

72-
export const escaped = {
73-
'"': '&quot;',
74-
"'": '&#39;',
75-
'&': '&amp;',
76-
'<': '&lt;',
77-
'>': '&gt;'
78-
};
79-
80-
export function escape(html) {
81-
return String(html).replace(/["'&<>]/g, match => escaped[match]);
72+
const ATTR_REGEX = /[&"]/g;
73+
const CONTENT_REGEX = /[&<]/g;
74+
75+
/**
76+
* Note: this method is performance sensitive and has been optimized
77+
* https://github.com/sveltejs/svelte/pull/5701
78+
*/
79+
export function escape(value: unknown, is_attr = false) {
80+
const str = String(value);
81+
82+
const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
83+
pattern.lastIndex = 0;
84+
85+
let escaped = '';
86+
let last = 0;
87+
88+
while (pattern.test(str)) {
89+
const i = pattern.lastIndex - 1;
90+
const ch = str[i];
91+
escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : (ch === '"' ? '&quot;' : '&lt;'));
92+
last = i + 1;
93+
}
94+
95+
return escaped + str.substring(last);
8296
}
8397

8498
export function escape_attribute_value(value) {
85-
return typeof value === 'string' ? escape(value) : value;
99+
return typeof value === 'string' ? escape(value, true) : value;
86100
}
87101

88102
export function escape_object(obj) {

0 commit comments

Comments
 (0)