Skip to content

Commit

Permalink
feat: allow const tag inside svelte:boundary (#14993)
Browse files Browse the repository at this point in the history
* feat: allow const tag inside `svelte:boundary`

* chore: add better test

* docs: update docs for `@const`
  • Loading branch information
paoloricciuti authored Jan 14, 2025
1 parent efa5acf commit a129592
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/curvy-lies-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: allow const tag inside `svelte:boundary`
2 changes: 1 addition & 1 deletion documentation/docs/03-template-syntax/09-@const.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ The `{@const ...}` tag defines a local constant.
{/each}
```

`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — or a `<Component />`.
`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — a `<Component />` or a `<svelte:boundary`.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function ConstTag(node, context) {
grand_parent?.type !== 'EachBlock' &&
grand_parent?.type !== 'AwaitBlock' &&
grand_parent?.type !== 'SnippetBlock' &&
grand_parent?.type !== 'SvelteBoundary' &&
((grand_parent?.type !== 'RegularElement' && grand_parent?.type !== 'SvelteElement') ||
!grand_parent.attributes.some((a) => a.type === 'Attribute' && a.name === 'slot')))
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,34 @@ export function SvelteBoundary(node, context) {
const nodes = [];

/** @type {Statement[]} */
const snippet_statements = [];
const external_statements = [];

const snippets_visits = [];

// Capture the `failed` implicit snippet prop
for (const child of node.fragment.nodes) {
if (child.type === 'SnippetBlock' && child.expression.name === 'failed') {
// we need to delay the visit of the snippets in case they access a ConstTag that is declared
// after the snippets so that the visitor for the const tag can be updated
snippets_visits.push(() => {
/** @type {Statement[]} */
const init = [];
context.visit(child, { ...context.state, init });
props.properties.push(b.prop('init', child.expression, child.expression));
external_statements.push(...init);
});
} else if (child.type === 'ConstTag') {
/** @type {Statement[]} */
const init = [];
context.visit(child, { ...context.state, init });
props.properties.push(b.prop('init', child.expression, child.expression));
snippet_statements.push(...init);
external_statements.push(...init);
} else {
nodes.push(child);
}
}

snippets_visits.forEach((visit) => visit());

const block = /** @type {BlockStatement} */ (context.visit({ ...node.fragment, nodes }));

const boundary = b.stmt(
Expand All @@ -56,6 +69,6 @@ export function SvelteBoundary(node, context) {

context.state.template.push('<!>');
context.state.init.push(
snippet_statements.length > 0 ? b.block([...snippet_statements, boundary]) : boundary
external_statements.length > 0 ? b.block([...external_statements, boundary]) : boundary
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
throw new Error();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
html: '<button></button><p>2</p>',
mode: ['client'],
test({ target, assert }) {
const btn = target.querySelector('button');
const p = target.querySelector('p');

flushSync(() => {
btn?.click();
});

assert.equal(p?.innerHTML, '4');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script>
import FlakyComponent from "./FlakyComponent.svelte";
let test=$state(1);
</script>

<button onclick={()=>test++}></button>

<svelte:boundary>
{@const double = test * 2}
{#snippet failed()}
<p>{double}</p>
{/snippet}
<FlakyComponent />
</svelte:boundary>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
let a = $state("");
</script>

<svelte:boundary>
{@const x = a}
{#snippet failed()}
{x}
{/snippet}
<FlakyComponent />
</svelte:boundary>

0 comments on commit a129592

Please sign in to comment.