only dewaterfall when necessary

pull/16757/head
Rich Harris 1 week ago
parent 9a273c6af2
commit 231af6a14b

@ -131,9 +131,6 @@ const visitors = {
ignore_map.set(node, structuredClone(ignore_stack)); ignore_map.set(node, structuredClone(ignore_stack));
const scope = state.scopes.get(node); const scope = state.scopes.get(node);
if (node.type === 'Fragment') {
node.metadata.hoisted_promises.name = state.scope.generate('promises');
}
next(scope !== undefined && scope !== state.scope ? { ...state, scope } : state); next(scope !== undefined && scope !== state.scope ? { ...state, scope } : state);
if (ignores.length > 0) { if (ignores.length > 0) {

@ -7,4 +7,18 @@
*/ */
export function Fragment(node, context) { export function Fragment(node, context) {
context.next({ ...context.state, fragment: node }); context.next({ ...context.state, fragment: node });
// TODO this indicates whether the fragment contains an `await` expression (not inside
// a child fragment), which is necessary for ensuring that a `SnippetBlock` creates an
// async function in SSR. It feels like this is probably duplicative, but it's late
// and it works, so for now I'm doing it like this
node.metadata.is_async = node.metadata.hoisted_promises.promises.length > 0;
if (node.metadata.hoisted_promises.promises.length > 1) {
node.metadata.hoisted_promises.name = context.state.scope.generate('promises');
} else {
// if there's only one promise in this fragment, we don't need to de-waterfall it
context.state.analysis.hoisted_promises.delete(node.metadata.hoisted_promises.promises[0]);
node.metadata.hoisted_promises.promises.length = 0;
}
} }

@ -12,7 +12,8 @@ export function SnippetBlock(node, context) {
let fn = b.function_declaration( let fn = b.function_declaration(
node.expression, node.expression,
[b.id('$$payload'), ...node.parameters], [b.id('$$payload'), ...node.parameters],
/** @type {BlockStatement} */ (context.visit(node.body)) /** @type {BlockStatement} */ (context.visit(node.body)),
node.body.metadata.is_async
); );
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone // @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone

@ -2,32 +2,21 @@ import * as $ from 'svelte/internal/server';
export default function Async_each_fallback_hoisting($$payload) { export default function Async_each_fallback_hoisting($$payload) {
$$payload.child(async ($$payload) => { $$payload.child(async ($$payload) => {
const promises = [Promise.resolve([])]; const each_array = $.ensure_array_like(await Promise.resolve([]));
const each_array = $.ensure_array_like(await promises[0]);
$$payload.child(async ($$payload) => {
if (each_array.length !== 0) { if (each_array.length !== 0) {
$$payload.push('<!--[-->'); $$payload.push('<!--[-->');
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
let item = each_array[$$index]; let item = each_array[$$index];
const promises_1 = [Promise.reject('This should never be reached')];
$$payload.child(async ($$payload) => { $$payload.push(`<!---->${$.escape(await Promise.reject('This should never be reached'))}`);
$$payload.push(`<!---->${$.escape(await promises_1[0])}`);
});
} }
} else { } else {
$$payload.push('<!--[!-->'); $$payload.push('<!--[!-->');
$$payload.push(`<!---->${$.escape(await Promise.resolve(4))}`);
const promises_2 = [Promise.resolve(4)];
$$payload.child(async ($$payload) => {
$$payload.push(`<!---->${$.escape(await promises_2[0])}`);
});
} }
$$payload.push(`<!--]-->`); $$payload.push(`<!--]-->`);
}); });
});
} }

@ -5,22 +5,16 @@ export default function Async_each_hoisting($$payload) {
const first = Promise.resolve(1); const first = Promise.resolve(1);
const second = Promise.resolve(2); const second = Promise.resolve(2);
const third = Promise.resolve(3); const third = Promise.resolve(3);
const promises = [Promise.resolve([first, second, third])]; const each_array = $.ensure_array_like(await Promise.resolve([first, second, third]));
const each_array = $.ensure_array_like(await promises[0]);
$$payload.child(async ($$payload) => {
$$payload.push(`<!--[-->`); $$payload.push(`<!--[-->`);
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
let item = each_array[$$index]; let item = each_array[$$index];
const promises_1 = [item];
$$payload.child(async ($$payload) => { $$payload.push(`<!---->${$.escape(await item)}`);
$$payload.push(`<!---->${$.escape(await promises_1[0])}`);
});
} }
$$payload.push(`<!--]-->`); $$payload.push(`<!--]-->`);
}); });
});
} }

@ -2,28 +2,14 @@ import * as $ from 'svelte/internal/server';
export default function Async_if_alternate_hoisting($$payload) { export default function Async_if_alternate_hoisting($$payload) {
$$payload.child(async ($$payload) => { $$payload.child(async ($$payload) => {
const promises = [Promise.resolve(false)]; if (await Promise.resolve(false)) {
$$payload.child(async ($$payload) => {
if (await promises[0]) {
$$payload.push('<!--[-->'); $$payload.push('<!--[-->');
$$payload.push(`${$.escape(await Promise.reject('no no no'))}`);
const promises_1 = [Promise.reject('no no no')];
$$payload.child(async ($$payload) => {
$$payload.push(`${$.escape(await promises_1[0])}`);
});
} else { } else {
$$payload.push('<!--[!-->'); $$payload.push('<!--[!-->');
$$payload.push(`${$.escape(await Promise.resolve('yes yes yes'))}`);
const promises_2 = [Promise.resolve('yes yes yes')];
$$payload.child(async ($$payload) => {
$$payload.push(`${$.escape(await promises_2[0])}`);
});
} }
$$payload.push(`<!--]-->`); $$payload.push(`<!--]-->`);
}); });
});
} }

@ -2,28 +2,14 @@ import * as $ from 'svelte/internal/server';
export default function Async_if_hoisting($$payload) { export default function Async_if_hoisting($$payload) {
$$payload.child(async ($$payload) => { $$payload.child(async ($$payload) => {
const promises = [Promise.resolve(true)]; if (await Promise.resolve(true)) {
$$payload.child(async ($$payload) => {
if (await promises[0]) {
$$payload.push('<!--[-->'); $$payload.push('<!--[-->');
$$payload.push(`${$.escape(await Promise.resolve('yes yes yes'))}`);
const promises_1 = [Promise.resolve('yes yes yes')];
$$payload.child(async ($$payload) => {
$$payload.push(`${$.escape(await promises_1[0])}`);
});
} else { } else {
$$payload.push('<!--[!-->'); $$payload.push('<!--[!-->');
$$payload.push(`${$.escape(await Promise.reject('no no no'))}`);
const promises_2 = [Promise.reject('no no no')];
$$payload.child(async ($$payload) => {
$$payload.push(`${$.escape(await promises_2[0])}`);
});
} }
$$payload.push(`<!--]-->`); $$payload.push(`<!--]-->`);
}); });
});
} }
Loading…
Cancel
Save