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>
pull/15383/head
adiGuba 6 months ago committed by GitHub
parent be82332ac8
commit fe343e9c50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: catch error on @const tag in svelte:boundary in DEV mode

@ -1,6 +1,7 @@
/** @import { BlockStatement, Statement, Expression } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import { dev } from '../../../../state.js';
import * as b from '../../../../utils/builders.js';
/**
@ -35,6 +36,9 @@ export function SvelteBoundary(node, context) {
/** @type {Statement[]} */
const external_statements = [];
/** @type {Statement[]} */
const internal_statements = [];
const snippets_visits = [];
// Capture the `failed` implicit snippet prop
@ -53,7 +57,20 @@ export function SvelteBoundary(node, context) {
/** @type {Statement[]} */
const init = [];
context.visit(child, { ...context.state, init });
if (dev) {
// In dev we must separate the declarations from the code
// that eagerly evaluate the expression...
for (const statement of init) {
if (statement.type === 'VariableDeclaration') {
external_statements.push(statement);
} else {
internal_statements.push(statement);
}
}
} else {
external_statements.push(...init);
}
} else {
nodes.push(child);
}
@ -63,6 +80,10 @@ export function SvelteBoundary(node, context) {
const block = /** @type {BlockStatement} */ (context.visit({ ...node.fragment, nodes }));
if (dev && internal_statements.length) {
block.body.unshift(...internal_statements);
}
const boundary = b.stmt(
b.call('$.boundary', context.state.node, props, b.arrow([b.id('$$anchor')], block))
);

@ -0,0 +1,33 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
// https://github.com/sveltejs/svelte/issues/15368
export default test({
compileOptions: {
dev: true
},
mode: ['client'],
html: `
<p>BOOM</p>
<p>BOOM</p>
<div>OK</div>
<div>OK</div>
`,
async test({ target, assert, component }) {
component.ok = false;
flushSync();
assert.htmlEqual(
target.innerHTML,
`
<p>BOOM</p>
<p>BOOM</p>
<p>BOOM</p>
<p>BOOM</p>
`
);
}
});

@ -0,0 +1,49 @@
<script>
let { ok = true } = $props();
function throwError() {
throw new Error();
}
function throwErrorOnUpdate() {
if (ok) {
return "OK";
} else {
throwError();
}
}
</script>
<svelte:boundary>
<div>{throwError()}</div>
{#snippet failed()}
<p>BOOM</p>
{/snippet}
</svelte:boundary>
<svelte:boundary>
{@const result = throwError()}
<div>{result}</div>
{#snippet failed()}
<p>BOOM</p>
{/snippet}
</svelte:boundary>
<svelte:boundary>
<div>{throwErrorOnUpdate()}</div>
{#snippet failed()}
<p>BOOM</p>
{/snippet}
</svelte:boundary>
<svelte:boundary>
{@const result = throwErrorOnUpdate()}
<div>{result}</div>
{#snippet failed()}
<p>BOOM</p>
{/snippet}
</svelte:boundary>
Loading…
Cancel
Save