Skip to content

Commit cd371ff

Browse files
committed
tidy up some SSR code
1 parent c9202a8 commit cd371ff

File tree

1 file changed

+42
-69
lines changed

1 file changed

+42
-69
lines changed

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 42 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,64 +1344,48 @@ const template_visitors = {
13441344

13451345
state.template.push(block_close);
13461346
},
1347-
ClassDirective(node) {
1347+
ClassDirective() {
13481348
throw new Error('Node should have been handled elsewhere');
13491349
},
1350-
StyleDirective(node) {
1350+
StyleDirective() {
13511351
throw new Error('Node should have been handled elsewhere');
13521352
},
13531353
RegularElement(node, context) {
1354-
const metadata = {
1355-
...context.state.metadata,
1356-
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
1357-
};
1358-
13591354
context.state.template.push(t_string(`<${node.name}`));
1360-
const body_expression = serialize_element_attributes(node, context);
1355+
const body = serialize_element_attributes(node, context);
13611356
context.state.template.push(t_string('>'));
13621357

1358+
const namespace = determine_namespace_for_children(node, context.state.metadata.namespace);
1359+
13631360
/** @type {import('./types').ComponentServerTransformState} */
13641361
const state = {
13651362
...context.state,
1366-
metadata,
1363+
metadata: { ...context.state.metadata, namespace },
13671364
preserve_whitespace:
13681365
context.state.preserve_whitespace ||
1369-
((node.name === 'pre' || node.name === 'textarea') && metadata.namespace !== 'foreign')
1366+
((node.name === 'pre' || node.name === 'textarea') && namespace !== 'foreign')
13701367
};
13711368

1372-
/** @type {import('./types').ComponentContext} */
1373-
const inner_context =
1374-
body_expression !== null
1375-
? {
1376-
...context,
1377-
state: {
1378-
...state,
1379-
template: [],
1380-
init: []
1381-
}
1382-
}
1383-
: { ...context, state };
1384-
13851369
const { hoisted, trimmed } = clean_nodes(
13861370
node,
13871371
node.fragment.nodes,
1388-
inner_context.path,
1389-
metadata.namespace,
1372+
context.path,
1373+
namespace,
13901374
{
1391-
...context.state,
1392-
scope: /** @type {import('../../scope').Scope} */ (context.state.scopes.get(node.fragment))
1375+
...state,
1376+
scope: /** @type {import('../../scope').Scope} */ (state.scopes.get(node.fragment))
13931377
},
13941378
state.preserve_whitespace,
13951379
state.options.preserveComments
13961380
);
13971381

13981382
for (const node of hoisted) {
1399-
inner_context.visit(node, state);
1383+
context.visit(node, state);
14001384
}
14011385

1402-
if (context.state.options.dev) {
1386+
if (state.options.dev) {
14031387
const location = /** @type {import('locate-character').Location} */ (locator(node.start));
1404-
context.state.template.push(
1388+
state.template.push(
14051389
t_statement(
14061390
b.stmt(
14071391
b.call(
@@ -1416,40 +1400,39 @@ const template_visitors = {
14161400
);
14171401
}
14181402

1419-
process_children(trimmed, node, inner_context);
1403+
if (body === null) {
1404+
process_children(trimmed, node, { ...context, state });
1405+
} else {
1406+
let id = body;
14201407

1421-
if (body_expression !== null) {
1422-
let body_id;
1423-
const expression = body_expression.escape
1424-
? b.call('$.escape', body_expression.expression)
1425-
: body_expression.expression;
1426-
if (expression.type === 'Identifier') {
1427-
body_id = expression;
1428-
} else {
1429-
body_id = b.id(context.state.scope.generate('$$body'));
1430-
context.state.template.push(t_statement(b.const(body_id, expression)));
1408+
if (body.type !== 'Identifier') {
1409+
id = b.id(state.scope.generate('$$body'));
1410+
state.template.push(t_statement(b.const(id, body)));
14311411
}
14321412

1413+
// if this is a `<textarea>` value or a contenteditable binding, we only add
1414+
// the body if the attribute/binding is falsy
1415+
const inner_state = { ...state, template: [], init: [] };
1416+
process_children(trimmed, node, { ...context, state: inner_state });
1417+
14331418
// Use the body expression as the body if it's truthy, otherwise use the inner template
1434-
context.state.template.push(
1419+
state.template.push(
14351420
t_statement(
14361421
b.if(
1437-
body_id,
1438-
b.block(serialize_template([t_expression(body_id)])),
1439-
b.block([
1440-
...inner_context.state.init,
1441-
...serialize_template(inner_context.state.template)
1442-
])
1422+
id,
1423+
b.block(serialize_template([t_expression(id)])),
1424+
b.block([...inner_state.init, ...serialize_template(inner_state.template)])
14431425
)
14441426
)
14451427
);
14461428
}
14471429

1448-
if (!VoidElements.includes(node.name) && metadata.namespace !== 'foreign') {
1449-
context.state.template.push(t_string(`</${node.name}>`));
1430+
if (!VoidElements.includes(node.name) && namespace !== 'foreign') {
1431+
state.template.push(t_string(`</${node.name}>`));
14501432
}
1451-
if (context.state.options.dev) {
1452-
context.state.template.push(t_statement(b.stmt(b.call('$.pop_element'))));
1433+
1434+
if (state.options.dev) {
1435+
state.template.push(t_statement(b.stmt(b.call('$.pop_element'))));
14531436
}
14541437
},
14551438
SvelteElement(node, context) {
@@ -1834,7 +1817,7 @@ function serialize_element_attributes(node, context) {
18341817
/** @type {import('estree').ExpressionStatement[]} */
18351818
const lets = [];
18361819

1837-
/** @type {{ escape: boolean; expression: import('estree').Expression } | null} */
1820+
/** @type {import('estree').Expression | null} */
18381821
let content = null;
18391822

18401823
let has_spread = false;
@@ -1857,10 +1840,7 @@ function serialize_element_attributes(node, context) {
18571840
// also see related code in analysis phase
18581841
attribute.value[0].data = '\n' + attribute.value[0].data;
18591842
}
1860-
content = {
1861-
escape: true,
1862-
expression: serialize_attribute_value(attribute.value, context)
1863-
};
1843+
content = b.call('$.escape', serialize_attribute_value(attribute.value, context));
18641844
} else if (node.name !== 'select') {
18651845
// omit value attribute for select elements, it's irrelevant for the initially selected value and has no
18661846
// effect on the selected value after the user interacts with the select element (the value _property_ does, but not the attribute)
@@ -1903,19 +1883,12 @@ function serialize_element_attributes(node, context) {
19031883
if (binding?.omit_in_ssr) continue;
19041884

19051885
if (ContentEditableBindings.includes(attribute.name)) {
1906-
content = {
1907-
escape: false,
1908-
expression: /** @type {import('estree').Expression} */ (
1909-
context.visit(attribute.expression)
1910-
)
1911-
};
1886+
content = /** @type {import('estree').Expression} */ (context.visit(attribute.expression));
19121887
} else if (attribute.name === 'value' && node.name === 'textarea') {
1913-
content = {
1914-
escape: true,
1915-
expression: /** @type {import('estree').Expression} */ (
1916-
context.visit(attribute.expression)
1917-
)
1918-
};
1888+
content = b.call(
1889+
'$.escape',
1890+
/** @type {import('estree').Expression} */ (context.visit(attribute.expression))
1891+
);
19191892
} else if (attribute.name === 'group') {
19201893
const value_attribute = /** @type {import('#compiler').Attribute | undefined} */ (
19211894
node.attributes.find((attr) => attr.type === 'Attribute' && attr.name === 'value')

0 commit comments

Comments
 (0)