use helper for async bodies (#16641)

* use helper for async bodies

* unused

* fix

* failing test + fix

---------

Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
pull/16619/head
Rich Harris 3 weeks ago committed by GitHub
parent af11ee5a47
commit ab5aedaddd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -359,16 +359,31 @@ export function client_component(analysis, options) {
if (dev) push_args.push(b.id(analysis.name));
let component_block = b.block([
store_init,
...store_setup,
...legacy_reactive_declarations,
...group_binding_declarations,
...state.instance_level_snippets,
.../** @type {ESTree.Statement[]} */ (instance.body),
analysis.runes || !analysis.needs_context
? b.empty
: b.stmt(b.call('$.init', analysis.immutable ? b.true : undefined))
...state.instance_level_snippets
]);
if (analysis.instance.has_await) {
const body = b.block([
.../** @type {ESTree.Statement[]} */ (instance.body),
b.if(b.call('$.aborted'), b.return()),
.../** @type {ESTree.Statement[]} */ (template.body)
]);
component_block.body.push(b.stmt(b.call(`$.async_body`, b.arrow([], body, true))));
} else {
component_block.body.push(.../** @type {ESTree.Statement[]} */ (instance.body));
if (!analysis.runes && analysis.needs_context) {
component_block.body.push(b.stmt(b.call('$.init', analysis.immutable ? b.true : undefined)));
}
component_block.body.push(.../** @type {ESTree.Statement[]} */ (template.body));
}
if (analysis.needs_mutation_validation) {
component_block.body.unshift(
b.var('$$ownership_validator', b.call('$.create_ownership_validator', b.id('$$props')))
@ -389,52 +404,6 @@ export function client_component(analysis, options) {
analysis.uses_slots ||
analysis.slot_names.size > 0;
if (analysis.instance.has_await) {
const params = [b.id('$$anchor')];
if (should_inject_props) {
params.push(b.id('$$props'));
}
if (store_setup.length > 0) {
params.push(b.id('$$stores'));
}
const body = b.function_declaration(
b.id('$$body'),
params,
b.block([
b.var('$$unsuspend', b.call('$.suspend')),
b.var('$$active', b.id('$.active_effect')),
b.try_catch(
b.block([
...component_block.body,
b.if(b.call('$.aborted'), b.return()),
.../** @type {ESTree.Statement[]} */ (template.body)
]),
b.block([
b.if(
b.unary('!', b.call('$.aborted', b.id('$$active'))),
b.stmt(b.call('$.invoke_error_boundary', b.id('$$error'), b.id('$$active')))
)
])
),
b.stmt(b.call('$$unsuspend'))
]),
true
);
state.hoisted.push(body);
component_block = b.block([
b.var('fragment', b.call('$.comment')),
b.var('node', b.call('$.first_child', b.id('fragment'))),
store_init,
b.stmt(b.call(body.id, b.id('node'), ...params.slice(1))),
b.stmt(b.call('$.append', b.id('$$anchor'), b.id('fragment')))
]);
} else {
component_block.body.unshift(store_init);
component_block.body.push(.../** @type {ESTree.Statement[]} */ (template.body));
}
// trick esrap into including comments
component_block.loc = instance.loc;

@ -659,24 +659,6 @@ export function throw_error(str) {
};
}
/**
* @param {ESTree.BlockStatement} body
* @param {ESTree.BlockStatement} handler
* @returns {ESTree.TryStatement}
*/
export function try_catch(body, handler) {
return {
type: 'TryStatement',
block: body,
handler: {
type: 'CatchClause',
param: id('$$error'),
body: handler
},
finalizer: null
};
}
export {
await_builder as await,
let_builder as let,

@ -99,6 +99,7 @@ export {
with_script
} from './dom/template.js';
export {
async_body,
for_await_track_reactivity_loss,
save,
track_reactivity_loss

@ -11,7 +11,7 @@ import {
set_active_effect,
set_active_reaction
} from '../runtime.js';
import { current_batch } from './batch.js';
import { current_batch, suspend } from './batch.js';
import {
async_derived,
current_async_effect,
@ -19,6 +19,7 @@ import {
derived_safe_equal,
set_from_async_derived
} from './deriveds.js';
import { aborted } from './effects.js';
/**
*
@ -170,3 +171,21 @@ export function unset_context() {
set_component_context(null);
if (DEV) set_from_async_derived(null);
}
/**
* @param {() => Promise<void>} fn
*/
export async function async_body(fn) {
const unsuspend = suspend();
const active = /** @type {Effect} */ (active_effect);
try {
await fn();
} catch (error) {
if (!aborted(active)) {
invoke_error_boundary(error, active);
}
} finally {
unsuspend();
}
}

@ -0,0 +1,9 @@
<script>
import { route } from "./main.svelte";
await new Promise(async (_, reject) => {
await Promise.resolve();
route.current = 'other'
route.reject = reject;
});
</script>

@ -0,0 +1,15 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
html: `<button>reject</button> <p>pending</p>`,
async test({ assert, target }) {
const [reject] = target.querySelectorAll('button');
await tick();
reject.click();
await tick();
assert.htmlEqual(target.innerHTML, '<button>reject</button> <p>route: other</p>');
}
});

@ -0,0 +1,18 @@
<script module>
import Child from './Child.svelte';
export let route = $state({ current: 'home' });
</script>
<button onclick={() => route.reject()}>reject</button>
<svelte:boundary>
{#if route.current === 'home'}
<Child />
{:else}
<p>route: {route.current}</p>
{/if}
{#snippet pending()}
<p>pending</p>
{/snippet}
</svelte:boundary>

@ -2,8 +2,6 @@
import { route } from "./main.svelte";
await new Promise(async (_, reject) => {
await Promise.resolve();
route.current = 'other'
route.reject = reject;
});
</script>

@ -7,9 +7,8 @@ export default test({
async test({ assert, target }) {
const [reject] = target.querySelectorAll('button');
await tick();
reject.click();
await tick();
assert.htmlEqual(target.innerHTML, '<button>reject</button> <p>route: other</p>');
assert.htmlEqual(target.innerHTML, '<button>reject</button> <p>failed</p>');
}
});

@ -1,18 +1,18 @@
<script module>
import Child from './Child.svelte';
export let route = $state({ current: 'home' });
export let route = $state({});
</script>
<button onclick={() => route.reject()}>reject</button>
<svelte:boundary>
{#if route.current === 'home'}
<Child />
{:else}
<p>route: {route.current}</p>
{/if}
<Child />
{#snippet pending()}
<p>pending</p>
{/snippet}
{#snippet failed()}
<p>failed</p>
{/snippet}
</svelte:boundary>

Loading…
Cancel
Save