Skip to content

Commit 84d1cfb

Browse files
committed
perf: inline default imports into template
1 parent 4791832 commit 84d1cfb

File tree

7 files changed

+37
-14
lines changed

7 files changed

+37
-14
lines changed

.changeset/seven-shrimps-explode.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 default imports into template

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,12 @@ export function create_derived(state, arg) {
314314

315315
/**
316316
* Whether a variable can be referenced directly from template string.
317-
* @param {import('#compiler').Binding | undefined} binding
317+
* @param {import('#compiler').Binding} binding
318318
* @returns {boolean}
319319
*/
320320
export function can_inline_variable(binding) {
321321
return (
322-
!!binding &&
323322
// in a `<script module>` block
324-
!binding.scope.parent &&
325-
// to prevent the need for escaping
326-
binding.initial?.type === 'Literal'
323+
!binding.scope.parent
327324
);
328325
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,9 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
631631
} else {
632632
if (inlinable_expression) {
633633
context.state.template.push_quasi(` ${name}="`);
634-
context.state.template.push_expression(value);
634+
context.state.template.push_expression(
635+
inlinable_expression.need_to_escape ? b.call('$.escape', value) : value
636+
);
635637
context.state.template.push_quasi('"');
636638
} else {
637639
state.init.push(update);
@@ -646,22 +648,24 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
646648
*/
647649
function is_inlinable_expression(nodes, state) {
648650
let has_expression_tag = false;
651+
let need_to_escape = false;
649652
for (let value of nodes) {
650653
if (value.type === 'ExpressionTag') {
651654
if (value.expression.type === 'Identifier') {
652655
const binding = state.scope
653656
.owner(value.expression.name)
654657
?.declarations.get(value.expression.name);
655-
if (!can_inline_variable(binding)) {
658+
if (!binding || !can_inline_variable(binding)) {
656659
return false;
657660
}
661+
need_to_escape = need_to_escape || binding.initial?.type !== 'Literal';
658662
} else {
659663
return false;
660664
}
661665
has_expression_tag = true;
662666
}
663667
}
664-
return has_expression_tag;
668+
return { need_to_escape };
665669
}
666670

667671
/**

packages/svelte/src/compiler/utils/sanitize_template_string.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Escape special characters like ` $ { \
23
* @param {string} str
34
* @returns {string}
45
*/
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
import "svelte/internal/disclose-version";
22
import * as $ from "svelte/internal/client";
3+
import __IMPORTED_ASSET_0__ from "./foo.svg";
4+
import { counter } from "./some.js";
35

46
const __DECLARED_ASSET_0__ = "__VITE_ASSET__2AM7_y_a__ 1440w, __VITE_ASSET__2AM7_y_b__ 960w";
57
const __DECLARED_ASSET_1__ = "__VITE_ASSET__2AM7_y_c__ 1440w, __VITE_ASSET__2AM7_y_d__ 960w";
68
const __DECLARED_ASSET_2__ = "__VITE_ASSET__2AM7_y_e__ 1440w, __VITE_ASSET__2AM7_y_f__ 960w";
79
const __DECLARED_ASSET_3__ = "__VITE_ASSET__2AM7_y_g__";
8-
var root = $.template(`<picture><source srcset="${__DECLARED_ASSET_0__}" type="image/avif"> <source srcset="${__DECLARED_ASSET_1__}" type="image/webp"> <source srcset="${__DECLARED_ASSET_2__}" type="image/png"> <img src="${__DECLARED_ASSET_3__}" alt="production test" width="1440" height="1440"></picture>`);
10+
var root = $.template(`<div></div> <img src="${$.escape(__IMPORTED_ASSET_0__)}" alt="default imports are not live bindings so can be inlined"> <picture><source srcset="${__DECLARED_ASSET_0__}" type="image/avif"> <source srcset="${__DECLARED_ASSET_1__}" type="image/webp"> <source srcset="${__DECLARED_ASSET_2__}" type="image/png"> <img src="${__DECLARED_ASSET_3__}" alt="production test" width="1440" height="1440"></picture>`, 1);
911

1012
export default function Inline_module_vars($$anchor) {
11-
var picture = root();
13+
var fragment = root();
14+
var div = $.first_child(fragment);
15+
16+
div.textContent = `${counter ?? ""} named exports are live bindings so cannot be inlined`;
17+
18+
var img = $.sibling(div, 2);
19+
var picture = $.sibling(img, 2);
1220
var source = $.child(picture);
1321
var source_1 = $.sibling(source, 2);
1422
var source_2 = $.sibling(source_1, 2);
15-
var img = $.sibling(source_2, 2);
23+
var img_1 = $.sibling(source_2, 2);
1624

1725
$.reset(picture);
18-
$.append($$anchor, picture);
19-
}
26+
$.append($$anchor, fragment);
27+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import * as $ from "svelte/internal/server";
2+
import __IMPORTED_ASSET_0__ from "./foo.svg";
3+
import { counter } from "./some.js";
24

35
const __DECLARED_ASSET_0__ = "__VITE_ASSET__2AM7_y_a__ 1440w, __VITE_ASSET__2AM7_y_b__ 960w";
46
const __DECLARED_ASSET_1__ = "__VITE_ASSET__2AM7_y_c__ 1440w, __VITE_ASSET__2AM7_y_d__ 960w";
57
const __DECLARED_ASSET_2__ = "__VITE_ASSET__2AM7_y_e__ 1440w, __VITE_ASSET__2AM7_y_f__ 960w";
68
const __DECLARED_ASSET_3__ = "__VITE_ASSET__2AM7_y_g__";
79

810
export default function Inline_module_vars($$payload) {
9-
$$payload.out += `<picture><source${$.attr("srcset", __DECLARED_ASSET_0__)} type="image/avif"> <source${$.attr("srcset", __DECLARED_ASSET_1__)} type="image/webp"> <source${$.attr("srcset", __DECLARED_ASSET_2__)} type="image/png"> <img${$.attr("src", __DECLARED_ASSET_3__)} alt="production test" width="1440" height="1440"></picture>`;
11+
$$payload.out += `<div>${$.escape(counter)} named exports are live bindings so cannot be inlined</div> <img${$.attr("src", __IMPORTED_ASSET_0__)} alt="default imports are not live bindings so can be inlined"> <picture><source${$.attr("srcset", __DECLARED_ASSET_0__)} type="image/avif"> <source${$.attr("srcset", __DECLARED_ASSET_1__)} type="image/webp"> <source${$.attr("srcset", __DECLARED_ASSET_2__)} type="image/png"> <img${$.attr("src", __DECLARED_ASSET_3__)} alt="production test" width="1440" height="1440"></picture>`;
1012
}

packages/svelte/tests/snapshot/samples/inline-module-vars/index.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
<svelte:options runes={true} />
22

33
<script module>
4+
import __IMPORTED_ASSET_0__ from "./foo.svg";
5+
import { counter } from "./some.js";
46
const __DECLARED_ASSET_0__ = "__VITE_ASSET__2AM7_y_a__ 1440w, __VITE_ASSET__2AM7_y_b__ 960w";
57
const __DECLARED_ASSET_1__ = "__VITE_ASSET__2AM7_y_c__ 1440w, __VITE_ASSET__2AM7_y_d__ 960w";
68
const __DECLARED_ASSET_2__ = "__VITE_ASSET__2AM7_y_e__ 1440w, __VITE_ASSET__2AM7_y_f__ 960w";
79
const __DECLARED_ASSET_3__ = "__VITE_ASSET__2AM7_y_g__";
810
</script>
911

12+
<div>{counter} named exports are live bindings so cannot be inlined</div>
13+
14+
<img src={__IMPORTED_ASSET_0__} alt="default imports are not live bindings so can be inlined" />
15+
1016
<picture>
1117
<source srcset={__DECLARED_ASSET_0__} type="image/avif" />
1218
<source srcset={__DECLARED_ASSET_1__} type="image/webp" />

0 commit comments

Comments
 (0)