From c43bfebcd7d7c24e4602c812346ac109eb6eec03 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 17 Apr 2025 22:22:45 +0200 Subject: [PATCH 1/8] fix: allow accessing snippet in script tag --- .changeset/few-horses-wink.md | 5 +++++ .../server/visitors/SnippetBlock.js | 19 +++++++++++-------- .../access-snippet-in-script/_config.js | 7 +++++++ .../samples/access-snippet-in-script/fn.js | 3 +++ .../access-snippet-in-script/main.svelte | 10 ++++++++++ svelte-renderer-api | 1 + 6 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 .changeset/few-horses-wink.md create mode 100644 packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js create mode 100644 packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte create mode 160000 svelte-renderer-api diff --git a/.changeset/few-horses-wink.md b/.changeset/few-horses-wink.md new file mode 100644 index 000000000000..dbd4e1f3f145 --- /dev/null +++ b/.changeset/few-horses-wink.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: allow accessing snippet in script tag diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js index 5118679b3489..3cb76143e1c7 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js @@ -1,4 +1,4 @@ -/** @import { ArrowFunctionExpression, BlockStatement, CallExpression } from 'estree' */ +/** @import { ArrowFunctionExpression, BlockStatement, CallExpression, Statement } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ import { dev } from '../../../../state.js'; @@ -15,21 +15,24 @@ export function SnippetBlock(node, context) { body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload')))); } - /** @type {ArrowFunctionExpression | CallExpression} */ - let fn = b.arrow([b.id('$$payload'), ...node.parameters], body); + let fn = b.function_declaration( + node.expression, + [b.id('$$payload'), ...node.parameters], + /** @type {BlockStatement} */ (context.visit(node.body)) + ); + + const push_to = node.metadata.can_hoist ? context.state.hoisted : context.state.init; if (dev) { - fn = b.call('$.prevent_snippet_stringification', fn); + push_to.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id))); } - const declaration = b.declaration('const', [b.declarator(node.expression, fn)]); - // @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone fn.___snippet = true; if (node.metadata.can_hoist) { - context.state.hoisted.push(declaration); + push_to.push(fn); } else { - context.state.init.push(declaration); + push_to.push(fn); } } diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js new file mode 100644 index 000000000000..ed0ead960bdb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js new file mode 100644 index 000000000000..9e9a48c60cbe --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js @@ -0,0 +1,3 @@ +export function fn(snippet) { + return snippet; +} diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte new file mode 100644 index 000000000000..cc73aa31db18 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte @@ -0,0 +1,10 @@ + + +{#snippet test()} + {variable} +{/snippet} \ No newline at end of file diff --git a/svelte-renderer-api b/svelte-renderer-api new file mode 160000 index 000000000000..97817a95d6fa --- /dev/null +++ b/svelte-renderer-api @@ -0,0 +1 @@ +Subproject commit 97817a95d6fa2d3f72c03f04a1e0882a7650cd16 From 110fef365fafa3bd4d2e006c935eee86ffd92b84 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:36:12 -0400 Subject: [PATCH 2/8] branches are identical --- .../3-transform/server/visitors/SnippetBlock.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js index 3cb76143e1c7..d37c9c3d8117 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js @@ -21,18 +21,14 @@ export function SnippetBlock(node, context) { /** @type {BlockStatement} */ (context.visit(node.body)) ); + // @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone + fn.___snippet = true; + const push_to = node.metadata.can_hoist ? context.state.hoisted : context.state.init; if (dev) { push_to.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id))); } - // @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone - fn.___snippet = true; - - if (node.metadata.can_hoist) { - push_to.push(fn); - } else { - push_to.push(fn); - } + push_to.push(fn); } From ccb4ca4c91750464db31c5fe4015ee5eb1f628cf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:39:45 -0400 Subject: [PATCH 3/8] update test --- .../bind-component-snippet/_expected/server/index.svelte.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js index 04bfbf6ae47b..cadae2cf15c0 100644 --- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js @@ -1,9 +1,9 @@ import * as $ from 'svelte/internal/server'; import TextInput from './Child.svelte'; -const snippet = ($$payload) => { +function snippet($$payload) { $$payload.out += `Something`; -}; +} export default function Bind_component_snippet($$payload) { let value = ''; From b90635b36824c06972dd6ea063e1d715bbb701d0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:40:34 -0400 Subject: [PATCH 4/8] rename test --- .../_config.js | 0 .../{access-snippet-in-script => snippet-access-in-script}/fn.js | 0 .../main.svelte | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename packages/svelte/tests/runtime-runes/samples/{access-snippet-in-script => snippet-access-in-script}/_config.js (100%) rename packages/svelte/tests/runtime-runes/samples/{access-snippet-in-script => snippet-access-in-script}/fn.js (100%) rename packages/svelte/tests/runtime-runes/samples/{access-snippet-in-script => snippet-access-in-script}/main.svelte (100%) diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/_config.js similarity index 100% rename from packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/_config.js rename to packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/_config.js diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js b/packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/fn.js similarity index 100% rename from packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/fn.js rename to packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/fn.js diff --git a/packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/main.svelte similarity index 100% rename from packages/svelte/tests/runtime-runes/samples/access-snippet-in-script/main.svelte rename to packages/svelte/tests/runtime-runes/samples/snippet-access-in-script/main.svelte From 4a6ea8b62635d78acc8a8daaa40a4938bde57823 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:43:57 -0400 Subject: [PATCH 5/8] fix validation (we were mutating the wrong array) --- .../phases/3-transform/server/visitors/SnippetBlock.js | 7 +------ .../samples/snippet-invalid-call/_config.js | 9 +++++++++ .../samples/snippet-invalid-call/main.svelte | 7 +++++++ 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/main.svelte diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js index d37c9c3d8117..1a104b138a70 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js @@ -9,12 +9,6 @@ import * as b from '#compiler/builders'; * @param {ComponentContext} context */ export function SnippetBlock(node, context) { - const body = /** @type {BlockStatement} */ (context.visit(node.body)); - - if (dev) { - body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload')))); - } - let fn = b.function_declaration( node.expression, [b.id('$$payload'), ...node.parameters], @@ -27,6 +21,7 @@ export function SnippetBlock(node, context) { const push_to = node.metadata.can_hoist ? context.state.hoisted : context.state.init; if (dev) { + fn.body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload')))); push_to.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id))); } diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/_config.js new file mode 100644 index 000000000000..7e72fd751ab6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + error: 'invalid_snippet_arguments' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/main.svelte new file mode 100644 index 000000000000..3c47db3f96eb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-invalid-call/main.svelte @@ -0,0 +1,7 @@ + + +{#snippet test()} +

hello

+{/snippet} From 68465a3d99ba790bd1bffa4a77aaaebbc3a84a50 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:44:41 -0400 Subject: [PATCH 6/8] tidy up --- .../phases/3-transform/server/visitors/SnippetBlock.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js index 1a104b138a70..238485e665b6 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SnippetBlock.js @@ -1,4 +1,4 @@ -/** @import { ArrowFunctionExpression, BlockStatement, CallExpression, Statement } from 'estree' */ +/** @import { BlockStatement } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ import { dev } from '../../../../state.js'; @@ -18,12 +18,12 @@ export function SnippetBlock(node, context) { // @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone fn.___snippet = true; - const push_to = node.metadata.can_hoist ? context.state.hoisted : context.state.init; + const statements = node.metadata.can_hoist ? context.state.hoisted : context.state.init; if (dev) { fn.body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload')))); - push_to.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id))); + statements.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id))); } - push_to.push(fn); + statements.push(fn); } From 10319580e16da1785ccfd09787e01c188f5371e9 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:46:38 -0400 Subject: [PATCH 7/8] remove submodule --- svelte-renderer-api | 1 - 1 file changed, 1 deletion(-) delete mode 160000 svelte-renderer-api diff --git a/svelte-renderer-api b/svelte-renderer-api deleted file mode 160000 index 97817a95d6fa..000000000000 --- a/svelte-renderer-api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 97817a95d6fa2d3f72c03f04a1e0882a7650cd16 From 7d5045b6364dc562403e5496e54dd86e0db4d1a9 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 17 Apr 2025 17:47:58 -0400 Subject: [PATCH 8/8] changeset --- .changeset/few-horses-wink.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/few-horses-wink.md b/.changeset/few-horses-wink.md index dbd4e1f3f145..8ffa3640c09f 100644 --- a/.changeset/few-horses-wink.md +++ b/.changeset/few-horses-wink.md @@ -2,4 +2,4 @@ 'svelte': patch --- -fix: allow accessing snippet in script tag +fix: use function declaration for snippets in server output to avoid TDZ violation