Skip to content

Commit 1d2f605

Browse files
committed
perf: inline module variables into template
1 parent 71c1227 commit 1d2f605

File tree

19 files changed

+154
-64
lines changed

19 files changed

+154
-64
lines changed

.changeset/eighty-dragons-search.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
perf: inline module variables into template

packages/svelte/src/compiler/phases/3-transform/client/types.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ export interface ComponentClientTransformState extends ClientTransformState {
5454
/** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */
5555
readonly after_update: Statement[];
5656
/** The HTML template string */
57-
readonly template: string[];
57+
readonly template: {
58+
quasi: string[];
59+
expressions: Expression[];
60+
};
5861
readonly locations: SourceLocation[];
5962
readonly metadata: {
6063
namespace: Namespace;

packages/svelte/src/compiler/phases/3-transform/client/utils.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,38 @@ export function create_derived_block_argument(node, context) {
311311
export function create_derived(state, arg) {
312312
return b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', arg);
313313
}
314+
315+
/**
316+
* @param {import('./types.js').ComponentClientTransformState} state
317+
* @param {string} quasi_to_add
318+
*/
319+
export function push_template_quasi(state, quasi_to_add) {
320+
const { quasi } = state.template;
321+
if (quasi.length === 0) {
322+
quasi.push(quasi_to_add);
323+
return;
324+
}
325+
quasi[quasi.length - 1] = quasi[quasi.length - 1].concat(quasi_to_add);
326+
}
327+
328+
/**
329+
* @param {import('./types.js').ComponentClientTransformState} state
330+
* @param {import('estree').Expression} expression_to_add
331+
*/
332+
export function push_template_expression(state, expression_to_add) {
333+
const { expressions, quasi } = state.template;
334+
if (quasi.length === 0) {
335+
quasi.push('');
336+
}
337+
expressions.push(expression_to_add);
338+
quasi.push('');
339+
}
340+
341+
/**
342+
* Whether a variable can be referenced directly from template string.
343+
* @param {import('#compiler').Binding | undefined} binding
344+
* @returns {boolean}
345+
*/
346+
export function can_inline_variable(binding) {
347+
return !!binding && !binding.scope.parent;
348+
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitBlock.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
44
import * as b from '../../../../utils/builders.js';
5-
import { create_derived_block_argument } from '../utils.js';
5+
import { create_derived_block_argument, push_template_quasi } from '../utils.js';
66

77
/**
88
* @param {AST.AwaitBlock} node
99
* @param {ComponentContext} context
1010
*/
1111
export function AwaitBlock(node, context) {
12-
context.state.template.push('<!>');
12+
push_template_quasi(context.state, '<!>');
1313

1414
// Visit {#await <expression>} first to ensure that scopes are in the correct order
1515
const expression = b.thunk(/** @type {Expression} */ (context.visit(node.expression)));
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/** @import { AST } from '#compiler' */
22
/** @import { ComponentContext } from '../types' */
33

4+
import { push_template_quasi } from '../utils.js';
5+
46
/**
57
* @param {AST.Comment} node
68
* @param {ComponentContext} context
79
*/
810
export function Comment(node, context) {
911
// We'll only get here if comments are not filtered out, which they are unless preserveComments is true
10-
context.state.template.push(`<!--${node.data}-->`);
12+
push_template_quasi(context.state, `<!--${node.data}-->`);
1113
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { dev } from '../../../../state.js';
1313
import { extract_paths, object } from '../../../../utils/ast.js';
1414
import * as b from '../../../../utils/builders.js';
15-
import { build_getter } from '../utils.js';
15+
import { build_getter, push_template_quasi } from '../utils.js';
1616
import { get_value } from './shared/declarations.js';
1717

1818
/**
@@ -32,7 +32,7 @@ export function EachBlock(node, context) {
3232
);
3333

3434
if (!each_node_meta.is_controlled) {
35-
context.state.template.push('<!>');
35+
push_template_quasi(context.state, '<!>');
3636
}
3737

3838
if (each_node_meta.array_name !== null) {

packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ export function Fragment(node, context) {
6464
init: [],
6565
update: [],
6666
after_update: [],
67-
template: [],
67+
template: {
68+
quasi: [],
69+
expressions: []
70+
},
6871
locations: [],
6972
transform: { ...context.state.transform },
7073
metadata: {
@@ -115,7 +118,12 @@ export function Fragment(node, context) {
115118
});
116119

117120
/** @type {Expression[]} */
118-
const args = [b.template([b.quasi(state.template.join(''), true)], [])];
121+
const args = [
122+
b.template(
123+
state.template.quasi.map((q) => b.quasi(q, true)),
124+
state.template.expressions
125+
)
126+
];
119127

120128
if (state.metadata.context.template_needs_import_node) {
121129
args.push(b.literal(TEMPLATE_USE_IMPORT_NODE));
@@ -170,12 +178,15 @@ export function Fragment(node, context) {
170178
flags |= TEMPLATE_USE_IMPORT_NODE;
171179
}
172180

173-
if (state.template.length === 1 && state.template[0] === '<!>') {
181+
if (state.template.quasi.length === 1 && state.template.quasi[0] === '<!>') {
174182
// special case — we can use `$.comment` instead of creating a unique template
175183
body.push(b.var(id, b.call('$.comment')));
176184
} else {
177185
add_template(template_name, [
178-
b.template([b.quasi(state.template.join(''), true)], []),
186+
b.template(
187+
state.template.quasi.map((q) => b.quasi(q, true)),
188+
state.template.expressions
189+
),
179190
b.literal(flags)
180191
]);
181192

packages/svelte/src/compiler/phases/3-transform/client/visitors/HtmlTag.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
/** @import { ComponentContext } from '../types' */
44
import { is_ignored } from '../../../../state.js';
55
import * as b from '../../../../utils/builders.js';
6+
import { push_template_quasi } from '../utils.js';
67

78
/**
89
* @param {AST.HtmlTag} node
910
* @param {ComponentContext} context
1011
*/
1112
export function HtmlTag(node, context) {
12-
context.state.template.push('<!>');
13+
push_template_quasi(context.state, '<!>');
1314

1415
// push into init, so that bindings run afterwards, which might trigger another run and override hydration
1516
context.state.init.push(

packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
44
import * as b from '../../../../utils/builders.js';
5+
import { push_template_quasi } from '../utils.js';
56

67
/**
78
* @param {AST.IfBlock} node
89
* @param {ComponentContext} context
910
*/
1011
export function IfBlock(node, context) {
11-
context.state.template.push('<!>');
12+
push_template_quasi(context.state, '<!>');
1213

1314
const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));
1415

packages/svelte/src/compiler/phases/3-transform/client/visitors/KeyBlock.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
44
import * as b from '../../../../utils/builders.js';
5+
import { push_template_quasi } from '../utils.js';
56

67
/**
78
* @param {AST.KeyBlock} node
89
* @param {ComponentContext} context
910
*/
1011
export function KeyBlock(node, context) {
11-
context.state.template.push('<!>');
12+
push_template_quasi(context.state, '<!>');
1213

1314
const key = /** @type {Expression} */ (context.visit(node.expression));
1415
const body = /** @type {Expression} */ (context.visit(node.fragment));

0 commit comments

Comments
 (0)