Skip to content

Commit fe343e9

Browse files
fix: catch error on @const tag in svelte:boundary in DEV mode (#15369)
* fix: catch error on @const tag in svelte:boundary * changeset * edit changeset * test * fix * rollback * simpler way to do that * rollback * roolback again --------- Co-authored-by: paoloricciuti <ricciutipaolo@gmail.com>
1 parent be82332 commit fe343e9

File tree

4 files changed

+109
-1
lines changed

4 files changed

+109
-1
lines changed

Diff for: .changeset/sixty-cats-search.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: catch error on @const tag in svelte:boundary in DEV mode

Diff for: packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteBoundary.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @import { BlockStatement, Statement, Expression } from 'estree' */
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
4+
import { dev } from '../../../../state.js';
45
import * as b from '../../../../utils/builders.js';
56

67
/**
@@ -35,6 +36,9 @@ export function SvelteBoundary(node, context) {
3536
/** @type {Statement[]} */
3637
const external_statements = [];
3738

39+
/** @type {Statement[]} */
40+
const internal_statements = [];
41+
3842
const snippets_visits = [];
3943

4044
// Capture the `failed` implicit snippet prop
@@ -53,7 +57,20 @@ export function SvelteBoundary(node, context) {
5357
/** @type {Statement[]} */
5458
const init = [];
5559
context.visit(child, { ...context.state, init });
56-
external_statements.push(...init);
60+
61+
if (dev) {
62+
// In dev we must separate the declarations from the code
63+
// that eagerly evaluate the expression...
64+
for (const statement of init) {
65+
if (statement.type === 'VariableDeclaration') {
66+
external_statements.push(statement);
67+
} else {
68+
internal_statements.push(statement);
69+
}
70+
}
71+
} else {
72+
external_statements.push(...init);
73+
}
5774
} else {
5875
nodes.push(child);
5976
}
@@ -63,6 +80,10 @@ export function SvelteBoundary(node, context) {
6380

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

83+
if (dev && internal_statements.length) {
84+
block.body.unshift(...internal_statements);
85+
}
86+
6687
const boundary = b.stmt(
6788
b.call('$.boundary', context.state.node, props, b.arrow([b.id('$$anchor')], block))
6889
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
// https://github.com/sveltejs/svelte/issues/15368
5+
export default test({
6+
compileOptions: {
7+
dev: true
8+
},
9+
10+
mode: ['client'],
11+
12+
html: `
13+
<p>BOOM</p>
14+
<p>BOOM</p>
15+
<div>OK</div>
16+
<div>OK</div>
17+
`,
18+
19+
async test({ target, assert, component }) {
20+
component.ok = false;
21+
flushSync();
22+
23+
assert.htmlEqual(
24+
target.innerHTML,
25+
`
26+
<p>BOOM</p>
27+
<p>BOOM</p>
28+
<p>BOOM</p>
29+
<p>BOOM</p>
30+
`
31+
);
32+
}
33+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script>
2+
let { ok = true } = $props();
3+
4+
function throwError() {
5+
throw new Error();
6+
}
7+
8+
function throwErrorOnUpdate() {
9+
if (ok) {
10+
return "OK";
11+
} else {
12+
throwError();
13+
}
14+
}
15+
</script>
16+
17+
<svelte:boundary>
18+
<div>{throwError()}</div>
19+
20+
{#snippet failed()}
21+
<p>BOOM</p>
22+
{/snippet}
23+
</svelte:boundary>
24+
25+
<svelte:boundary>
26+
{@const result = throwError()}
27+
<div>{result}</div>
28+
29+
{#snippet failed()}
30+
<p>BOOM</p>
31+
{/snippet}
32+
</svelte:boundary>
33+
34+
<svelte:boundary>
35+
<div>{throwErrorOnUpdate()}</div>
36+
37+
{#snippet failed()}
38+
<p>BOOM</p>
39+
{/snippet}
40+
</svelte:boundary>
41+
42+
<svelte:boundary>
43+
{@const result = throwErrorOnUpdate()}
44+
<div>{result}</div>
45+
46+
{#snippet failed()}
47+
<p>BOOM</p>
48+
{/snippet}
49+
</svelte:boundary>

0 commit comments

Comments
 (0)