diff --git a/.changeset/eighty-days-cheat.md b/.changeset/eighty-days-cheat.md new file mode 100644 index 0000000000..1dab9a948f --- /dev/null +++ b/.changeset/eighty-days-cheat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: improve template literal expression output generation diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 2ecec2eeb3..19fef4e5bd 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -615,6 +615,7 @@ export function should_proxy_or_freeze(node) { if ( !node || node.type === 'Literal' || + node.type === 'TemplateLiteral' || node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression' || node.type === 'UnaryExpression' || diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 8c3cb748c4..b6708bc851 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -1663,6 +1663,11 @@ function serialize_template_literal(values, visit, state) { if (node.type === 'Text') { const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1)); last.value.raw += sanitize_template_string(node.data); + } else if (node.type === 'ExpressionTag' && node.expression.type === 'Literal') { + const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1)); + if (node.expression.value != null) { + last.value.raw += sanitize_template_string(node.expression.value + ''); + } } else { if (node.type === 'ExpressionTag' && node.metadata.contains_call_expression) { contains_call_expression = true; diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 30da7f35bb..2062095235 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -2803,7 +2803,7 @@ export function mount(component, options) { ).c = options.context; } // @ts-expect-error the public typings are not what the actual function looks like - accessors = component(anchor, options.props || {}, options.events || {}); + accessors = component(anchor, options.props || {}); if (options.context) { pop(); } diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js index e233a9d51e..f0960dc93d 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js @@ -45,4 +45,4 @@ export default function Main($$anchor, $$props) { $.close_frag($$anchor, fragment); $.pop(); -} +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_config.js b/packages/svelte/tests/snapshot/samples/each-string-template/_config.js new file mode 100644 index 0000000000..f47bee71df --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js new file mode 100644 index 0000000000..5680d12e63 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -0,0 +1,30 @@ +// index.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import "svelte/internal/disclose-version"; +import * as $ from "svelte/internal"; + +export default function Each_string_template($$anchor, $$props) { + $.push($$props, false); + + /* Init */ + var fragment = $.comment($$anchor); + var node = $.child_frag(fragment); + + $.each_indexed( + node, + () => ['foo', 'bar', 'baz'], + 1, + ($$anchor, thing, $$index) => { + /* Init */ + var node_1 = $.space($$anchor); + + /* Update */ + $.text_effect(node_1, () => `${$.stringify($.unwrap(thing))}, `); + $.close($$anchor, node_1); + }, + null + ); + + $.close_frag($$anchor, fragment); + $.pop(); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js new file mode 100644 index 0000000000..a4bbf5a982 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js @@ -0,0 +1,22 @@ +// index.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import * as $ from "svelte/internal/server"; + +export default function Each_string_template($$payload, $$props) { + $.push(false); + + const anchor = $.create_anchor($$payload); + const each_array = $.ensure_array_like(['foo', 'bar', 'baz']); + + $$payload.out += `${anchor}`; + + for (let $$index = 0; $$index < each_array.length; $$index++) { + const thing = each_array[$$index]; + const anchor_1 = $.create_anchor($$payload); + + $$payload.out += `${anchor_1}${$.escape(thing)},${$.escape(' ')}${anchor_1}`; + } + + $$payload.out += `${anchor}`; + $.pop(); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/index.svelte b/packages/svelte/tests/snapshot/samples/each-string-template/index.svelte new file mode 100644 index 0000000000..f2ab129af6 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/each-string-template/index.svelte @@ -0,0 +1,3 @@ +{#each ['foo', 'bar', 'baz'] as thing} + {thing},{' '} +{/each} diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_config.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_config.js new file mode 100644 index 0000000000..f47bee71df --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js new file mode 100644 index 0000000000..f1a5a0ee42 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js @@ -0,0 +1,39 @@ +// index.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import "svelte/internal/disclose-version"; +import * as $ from "svelte/internal"; + +function reset(_, str, tpl) { + $.set(str, ''); + $.set(str, ``); + $.set(tpl, ''); + $.set(tpl, ``); +} + +var frag = $.template(` `, true); + +export default function State_proxy_literal($$anchor, $$props) { + $.push($$props, true); + + let str = $.source(''); + let tpl = $.source(``); + /* Init */ + var fragment = $.open_frag($$anchor, true, frag); + var node = $.child_frag(fragment); + + $.remove_input_attr_defaults(node); + + var input = $.sibling($.sibling(node)); + + $.remove_input_attr_defaults(input); + + var button = $.sibling($.sibling(input)); + + $.bind_value(node, () => $.get(str), ($$value) => $.set(str, $.proxy($$value))); + $.bind_value(input, () => $.get(tpl), ($$value) => $.set(tpl, $.proxy($$value))); + button.__click = [reset, str, tpl]; + $.close_frag($$anchor, fragment); + $.pop(); +} + +$.delegate(["click"]); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js new file mode 100644 index 0000000000..c541299e36 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/server/index.svelte.js @@ -0,0 +1,20 @@ +// index.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import * as $ from "svelte/internal/server"; + +export default function State_proxy_literal($$payload, $$props) { + $.push(true); + + let str = ''; + let tpl = ``; + + function reset() { + str = ''; + str = ``; + tpl = ''; + tpl = ``; + } + + $$payload.out += ` `; + $.pop(); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/index.svelte b/packages/svelte/tests/snapshot/samples/state-proxy-literal/index.svelte new file mode 100644 index 0000000000..155682f955 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/index.svelte @@ -0,0 +1,17 @@ + + + + + + diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index 937e22410f..6fcc18c0c4 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -14,4 +14,4 @@ export default function Svelte_element($$anchor, $$props) { $.element(node, tag); $.close_frag($$anchor, fragment); $.pop(); -} +} \ No newline at end of file