Skip to content

Commit 7f473f6

Browse files
fix: allow accessing snippet in script tag (#15789)
* fix: allow accessing snippet in script tag * branches are identical * update test * rename test * fix validation (we were mutating the wrong array) * tidy up * remove submodule * changeset --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 707682e commit 7f473f6

File tree

8 files changed

+55
-20
lines changed

8 files changed

+55
-20
lines changed

.changeset/few-horses-wink.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: use function declaration for snippets in server output to avoid TDZ violation
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { ArrowFunctionExpression, BlockStatement, CallExpression } from 'estree' */
1+
/** @import { BlockStatement } from 'estree' */
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types.js' */
44
import { dev } from '../../../../state.js';
@@ -9,27 +9,21 @@ import * as b from '#compiler/builders';
99
* @param {ComponentContext} context
1010
*/
1111
export function SnippetBlock(node, context) {
12-
const body = /** @type {BlockStatement} */ (context.visit(node.body));
12+
let fn = b.function_declaration(
13+
node.expression,
14+
[b.id('$$payload'), ...node.parameters],
15+
/** @type {BlockStatement} */ (context.visit(node.body))
16+
);
1317

14-
if (dev) {
15-
body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload'))));
16-
}
18+
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
19+
fn.___snippet = true;
1720

18-
/** @type {ArrowFunctionExpression | CallExpression} */
19-
let fn = b.arrow([b.id('$$payload'), ...node.parameters], body);
21+
const statements = node.metadata.can_hoist ? context.state.hoisted : context.state.init;
2022

2123
if (dev) {
22-
fn = b.call('$.prevent_snippet_stringification', fn);
24+
fn.body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload'))));
25+
statements.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id)));
2326
}
2427

25-
const declaration = b.declaration('const', [b.declarator(node.expression, fn)]);
26-
27-
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
28-
fn.___snippet = true;
29-
30-
if (node.metadata.can_hoist) {
31-
context.state.hoisted.push(declaration);
32-
} else {
33-
context.state.init.push(declaration);
34-
}
28+
statements.push(fn);
3529
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
compileOptions: {
5+
dev: true
6+
}
7+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function fn(snippet) {
2+
return snippet;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
import { fn } from "./fn.js";
3+
let variable = $state("var");
4+
5+
fn(test);
6+
</script>
7+
8+
{#snippet test()}
9+
{variable}
10+
{/snippet}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
compileOptions: {
5+
dev: true
6+
},
7+
8+
error: 'invalid_snippet_arguments'
9+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
test();
3+
</script>
4+
5+
{#snippet test()}
6+
<p>hello</p>
7+
{/snippet}

packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import * as $ from 'svelte/internal/server';
22
import TextInput from './Child.svelte';
33

4-
const snippet = ($$payload) => {
4+
function snippet($$payload) {
55
$$payload.out += `<!---->Something`;
6-
};
6+
}
77

88
export default function Bind_component_snippet($$payload) {
99
let value = '';

0 commit comments

Comments
 (0)