Merge branch 'main' into async-hydration-resolved

pull/17640/head
Simon H 1 day ago committed by GitHub
commit d6421cbd0d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: properly hydrate already-resolved async blocks

@ -166,6 +166,7 @@ export function client_component(analysis, options) {
in_constructor: false,
instance_level_snippets: [],
module_level_snippets: [],
is_standalone: false,
// these are set inside the `Fragment` visitor, and cannot be used until then
init: /** @type {any} */ (null),

@ -83,6 +83,9 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly instance_level_snippets: VariableDeclaration[];
/** Snippets hoisted to the module */
readonly module_level_snippets: VariableDeclaration[];
/** True if the current node is a) a component or render tag and b) the sole child of a block */
readonly is_standalone: boolean;
}
export type Context = import('zimmerframe').Context<AST.SvelteNode, ClientTransformState>;

@ -120,34 +120,35 @@ export function Fragment(node, context) {
state.init.unshift(b.var(id, b.call('$.text')));
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
} else if (is_standalone) {
// no need to create a template, we can just use the existing block's anchor
process_children(trimmed, () => b.id('$$anchor'), false, {
...context,
state: { ...state, is_standalone }
});
} else {
if (is_standalone) {
// no need to create a template, we can just use the existing block's anchor
process_children(trimmed, () => b.id('$$anchor'), false, { ...context, state });
} else {
/** @type {(is_text: boolean) => Expression} */
const expression = (is_text) => b.call('$.first_child', id, is_text && b.true);
process_children(trimmed, expression, false, { ...context, state });
/** @type {(is_text: boolean) => Expression} */
const expression = (is_text) => b.call('$.first_child', id, is_text && b.true);
let flags = TEMPLATE_FRAGMENT;
process_children(trimmed, expression, false, { ...context, state });
if (state.template.needs_import_node) {
flags |= TEMPLATE_USE_IMPORT_NODE;
}
let flags = TEMPLATE_FRAGMENT;
if (state.template.nodes.length === 1 && state.template.nodes[0].type === 'comment') {
// special case — we can use `$.comment` instead of creating a unique template
state.init.unshift(b.var(id, b.call('$.comment')));
} else {
const template = transform_template(state, namespace, flags);
state.hoisted.push(b.var(template_name, template));
if (state.template.needs_import_node) {
flags |= TEMPLATE_USE_IMPORT_NODE;
}
state.init.unshift(b.var(id, b.call(template_name)));
}
if (state.template.nodes.length === 1 && state.template.nodes[0].type === 'comment') {
// special case — we can use `$.comment` instead of creating a unique template
state.init.unshift(b.var(id, b.call('$.comment')));
} else {
const template = transform_template(state, namespace, flags);
state.hoisted.push(b.var(template_name, template));
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
state.init.unshift(b.var(id, b.call(template_name)));
}
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
}
}

@ -85,6 +85,10 @@ export function RenderTag(node, context) {
)
)
);
if (context.state.is_standalone) {
context.state.init.push(b.stmt(b.call('$.next')));
}
} else {
context.state.init.push(statements.length === 1 ? statements[0] : b.block(statements));
}

@ -461,7 +461,7 @@ export function build_component(node, component_name, loc, context) {
memoizer.check_blockers(node.metadata.expression);
}
const statements = [...snippet_declarations, ...memoizer.deriveds(context.state.analysis.runes)];
let statements = [...snippet_declarations, ...memoizer.deriveds(context.state.analysis.runes)];
if (is_component_dynamic) {
const prev = fn;
@ -515,15 +515,21 @@ export function build_component(node, component_name, loc, context) {
const blockers = memoizer.blockers();
if (async_values || blockers) {
return b.stmt(
b.call(
'$.async',
anchor,
blockers,
async_values,
b.arrow([b.id('$$anchor'), ...memoizer.async_ids()], b.block(statements))
statements = [
b.stmt(
b.call(
'$.async',
anchor,
blockers,
async_values,
b.arrow([b.id('$$anchor'), ...memoizer.async_ids()], b.block(statements))
)
)
);
];
if (context.state.is_standalone) {
statements.push(b.stmt(b.call('$.next')));
}
}
return statements.length > 1 ? b.block(statements) : statements[0];

@ -41,7 +41,6 @@ import { TitleElement } from './visitors/TitleElement.js';
import { UpdateExpression } from './visitors/UpdateExpression.js';
import { VariableDeclaration } from './visitors/VariableDeclaration.js';
import { SvelteBoundary } from './visitors/SvelteBoundary.js';
import { call_component_renderer } from './visitors/shared/utils.js';
/** @type {Visitors} */
const global_visitors = {
@ -105,7 +104,7 @@ export function server_component(analysis, options) {
namespace: options.namespace,
preserve_whitespace: options.preserveWhitespace,
state_fields: new Map(),
skip_hydration_boundaries: false,
is_standalone: false,
is_instance: false
};
@ -260,7 +259,13 @@ export function server_component(analysis, options) {
if (should_inject_context) {
component_block = b.block([
call_component_renderer(component_block, dev && b.id(component_name))
b.stmt(
b.call(
'$$renderer.component',
b.arrow([b.id('$$renderer')], component_block, false),
dev && b.id(component_name)
)
)
]);
}

@ -26,7 +26,8 @@ export interface ComponentServerTransformState extends ServerTransformState {
readonly template: Array<Statement | Expression>;
readonly namespace: Namespace;
readonly preserve_whitespace: boolean;
readonly skip_hydration_boundaries: boolean;
/** True if the current node is a) a component or render tag and b) the sole child of a block */
readonly is_standalone: boolean;
/** Transformed async `{@const }` declarations (if any) and those coming after them */
async_consts?: {
id: Identifier;

@ -2,7 +2,7 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
import * as b from '#compiler/builders';
import { block_close, create_async_block } from './shared/utils.js';
import { block_close, create_child_block } from './shared/utils.js';
/**
* @param {AST.AwaitBlock} node
@ -25,13 +25,12 @@ export function AwaitBlock(node, context) {
)
);
if (node.metadata.expression.is_async()) {
statement = create_async_block(
b.block([statement]),
context.state.template.push(
...create_child_block(
[statement],
node.metadata.expression.blockers(),
node.metadata.expression.has_await
);
}
context.state.template.push(statement, block_close);
),
block_close
);
}

@ -2,7 +2,7 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
import * as b from '#compiler/builders';
import { block_close, block_open, block_open_else, create_async_block } from './shared/utils.js';
import { block_close, block_open, block_open_else, create_child_block } from './shared/utils.js';
/**
* @param {AST.EachBlock} node
@ -18,8 +18,8 @@ export function EachBlock(node, context) {
const array_id = state.scope.root.unique('each_array');
/** @type {Statement} */
let block = b.block([b.const(array_id, b.call('$.ensure_array_like', collection))]);
/** @type {Statement[]} */
let statements = [b.const(array_id, b.call('$.ensure_array_like', collection))];
/** @type {Statement[]} */
const each = [];
@ -53,7 +53,7 @@ export function EachBlock(node, context) {
fallback.body.unshift(b.stmt(b.call(b.id('$$renderer.push'), block_open_else)));
block.body.push(
statements.push(
b.if(
b.binary('!==', b.member(array_id, 'length'), b.literal(0)),
b.block([open, for_loop]),
@ -62,19 +62,15 @@ export function EachBlock(node, context) {
);
} else {
state.template.push(block_open);
block.body.push(for_loop);
statements.push(for_loop);
}
if (node.metadata.expression.is_async()) {
state.template.push(
create_async_block(
block,
node.metadata.expression.blockers(),
node.metadata.expression.has_await
),
block_close
);
} else {
state.template.push(...block.body, block_close);
}
state.template.push(
...create_child_block(
statements,
node.metadata.expression.blockers(),
node.metadata.expression.has_await
),
block_close
);
}

@ -28,7 +28,7 @@ export function Fragment(node, context) {
init: [],
template: [],
namespace,
skip_hydration_boundaries: is_standalone,
is_standalone,
async_consts: undefined
};

@ -2,25 +2,24 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
import * as b from '#compiler/builders';
import { block_close, block_open, create_push } from './shared/utils.js';
import { create_child_block } from './shared/utils.js';
/**
* @param {AST.HtmlTag} node
* @param {ComponentContext} context
*/
export function HtmlTag(node, context) {
const expression = /** @type {Expression} */ (context.visit(node.expression));
const call = b.call('$.html', expression);
const expression = b.call('$.html', /** @type {Expression} */ (context.visit(node.expression)));
const has_await = node.metadata.expression.has_await;
if (has_await) {
context.state.template.push(block_open);
}
context.state.template.push(create_push(call, node.metadata.expression, true));
if (has_await) {
context.state.template.push(block_close);
if (node.metadata.expression.is_async()) {
context.state.template.push(
...create_child_block(
[b.stmt(b.call('$$renderer.push', expression))],
node.metadata.expression.blockers(),
node.metadata.expression.has_await
)
);
} else {
context.state.template.push(expression);
}
}

@ -2,7 +2,7 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
import * as b from '#compiler/builders';
import { block_close, block_open, block_open_else, create_async_block } from './shared/utils.js';
import { block_close, block_open, block_open_else, create_child_block } from './shared/utils.js';
/**
* @param {AST.IfBlock} node
@ -23,17 +23,12 @@ export function IfBlock(node, context) {
/** @type {Statement} */
let statement = b.if(test, consequent, alternate);
const is_async = node.metadata.expression.is_async();
const has_await = node.metadata.expression.has_await;
if (is_async || has_await) {
statement = create_async_block(
b.block([statement]),
context.state.template.push(
...create_child_block(
[statement],
node.metadata.expression.blockers(),
!!has_await
);
}
context.state.template.push(statement, block_close);
node.metadata.expression.has_await
),
block_close
);
}

@ -1,5 +1,4 @@
/** @import { Expression } from 'estree' */
/** @import { Location } from 'locate-character' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext, ComponentServerTransformState } from '../types.js' */
/** @import { Scope } from '../../../scope.js' */
@ -8,13 +7,7 @@ import { dev, locator } from '../../../../state.js';
import * as b from '#compiler/builders';
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
import { build_element_attributes, prepare_element_spread_object } from './shared/element.js';
import {
process_children,
build_template,
create_child_block,
PromiseOptimiser,
create_async_block
} from './shared/utils.js';
import { process_children, build_template, PromiseOptimiser } from './shared/utils.js';
import { is_customizable_select_element } from '../../../nodes.js';
/**
@ -66,17 +59,9 @@ export function RegularElement(node, context) {
b.literal(`</${node.name}>`)
);
// TODO this is a real edge case, would be good to DRY this out
if (optimiser.expressions.length > 0) {
context.state.template.push(
create_child_block(
b.block([optimiser.apply(), ...state.init, ...build_template(state.template)])
)
);
} else {
context.state.init.push(...state.init);
context.state.template.push(...state.template);
}
context.state.template.push(
...optimiser.render([...state.init, ...build_template(state.template)])
);
return;
}
@ -130,13 +115,7 @@ export function RegularElement(node, context) {
const statement = b.stmt(b.call('$$renderer.select', attributes, fn, ...rest));
if (optimiser.expressions.length > 0) {
context.state.template.push(
create_child_block(b.block([optimiser.apply(), ...state.init, statement]))
);
} else {
context.state.template.push(...state.init, statement);
}
context.state.template.push(...optimiser.render([...state.init, statement]));
return;
}
@ -183,13 +162,7 @@ export function RegularElement(node, context) {
const statement = b.stmt(b.call('$$renderer.option', attributes, body, ...rest));
if (optimiser.expressions.length > 0) {
context.state.template.push(
create_child_block(b.block([optimiser.apply(), ...state.init, statement]))
);
} else {
context.state.template.push(...state.init, statement);
}
context.state.template.push(...optimiser.render([...state.init, statement]));
return;
}
@ -235,19 +208,9 @@ export function RegularElement(node, context) {
}
if (optimiser.is_async()) {
let statements = [...state.init, ...build_template(state.template)];
if (optimiser.has_await) {
statements = [create_child_block(b.block([optimiser.apply(), ...statements]))];
}
const blockers = optimiser.blockers();
if (blockers.elements.length > 0) {
statements = [create_async_block(b.block(statements), blockers, false, false)];
}
context.state.template.push(...statements);
context.state.template.push(
...optimiser.render([...state.init, ...build_template(state.template)])
);
} else {
context.state.init.push(...state.init);
context.state.template.push(...state.template);

@ -3,7 +3,7 @@
/** @import { ComponentContext } from '../types.js' */
import { unwrap_optional } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
import { create_async_block, empty_comment, PromiseOptimiser } from './shared/utils.js';
import { empty_comment, PromiseOptimiser } from './shared/utils.js';
/**
* @param {AST.RenderTag} node
@ -35,17 +35,9 @@ export function RenderTag(node, context) {
)
);
if (optimiser.is_async()) {
statement = create_async_block(
b.block([optimiser.apply(), statement]),
optimiser.blockers(),
optimiser.has_await
);
}
context.state.template.push(statement);
context.state.template.push(...optimiser.render_block([statement]));
if (!context.state.skip_hydration_boundaries) {
if (!context.state.is_standalone) {
context.state.template.push(empty_comment);
}
}

@ -5,7 +5,6 @@ import * as b from '#compiler/builders';
import {
build_attribute_value,
PromiseOptimiser,
create_async_block,
block_open,
block_close
} from './shared/utils.js';
@ -65,13 +64,5 @@ export function SlotElement(node, context) {
fallback
);
const statement = optimiser.is_async()
? create_async_block(
b.block([optimiser.apply(), b.stmt(slot)]),
optimiser.blockers(),
optimiser.has_await
)
: b.stmt(slot);
context.state.template.push(block_open, statement, block_close);
context.state.template.push(block_open, ...optimiser.render_block([b.stmt(slot)]), block_close);
}

@ -1,4 +1,3 @@
/** @import { Location } from 'locate-character' */
/** @import { BlockStatement, Expression, Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
@ -6,12 +5,7 @@ import { dev, locator } from '../../../../state.js';
import * as b from '#compiler/builders';
import { determine_namespace_for_children } from '../../utils.js';
import { build_element_attributes } from './shared/element.js';
import {
build_template,
create_async_block,
create_child_block,
PromiseOptimiser
} from './shared/utils.js';
import { build_template, create_child_block, PromiseOptimiser } from './shared/utils.js';
/**
* @param {AST.SvelteElement} node
@ -67,36 +61,29 @@ export function SvelteElement(node, context) {
const attributes = b.block([...state.init, ...build_template(state.template)]);
const children = /** @type {BlockStatement} */ (context.visit(node.fragment, state));
/** @type {Statement} */
let statement = b.stmt(
b.call(
'$.element',
b.id('$$renderer'),
tag,
attributes.body.length > 0 && b.thunk(attributes),
children.body.length > 0 && b.thunk(children)
)
statements.push(
...optimiser.render([
b.stmt(
b.call(
'$.element',
b.id('$$renderer'),
tag,
attributes.body.length > 0 && b.thunk(attributes),
children.body.length > 0 && b.thunk(children)
)
)
])
);
if (optimiser.expressions.length > 0) {
statement = create_child_block(b.block([optimiser.apply(), statement]));
}
statements.push(statement);
if (dev) {
statements.push(b.stmt(b.call('$.pop_element')));
}
if (node.metadata.expression.is_async()) {
statements = [
create_async_block(
b.block(statements),
node.metadata.expression.blockers(),
node.metadata.expression.has_await
)
];
}
context.state.template.push(...statements);
context.state.template.push(
...create_child_block(
statements,
node.metadata.expression.blockers(),
node.metadata.expression.has_await
)
);
}

@ -1,12 +1,7 @@
/** @import { BlockStatement, Expression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../../types.js' */
import {
empty_comment,
build_attribute_value,
create_async_block,
PromiseOptimiser
} from './utils.js';
import { empty_comment, build_attribute_value, PromiseOptimiser } from './utils.js';
import * as b from '#compiler/builders';
import { is_element_node } from '../../../../nodes.js';
import { dev } from '../../../../../state.js';
@ -106,10 +101,16 @@ export function build_inline_component(node, expression, context) {
}
push_prop(b.prop('init', b.key(attribute.name), value));
} else if (attribute.type === 'BindDirective' && attribute.name !== 'this') {
} else if (attribute.type === 'BindDirective') {
// Bindings are a bit special: we don't want to add them to (async) deriveds but we need to check if they have blockers
optimiser.check_blockers(attribute.metadata.expression);
if (attribute.name === 'this') {
// bind:this is client-only, but we still need to check for blockers to ensure
// the server generates matching hydration markers if the client wraps in $.async
continue;
}
if (attribute.expression.type === 'SequenceExpression') {
const [get, set] = /** @type {SequenceExpression} */ (context.visit(attribute.expression))
.expressions;
@ -325,32 +326,16 @@ export function build_inline_component(node, expression, context) {
optimiser.check_blockers(node.metadata.expression);
}
const is_async = optimiser.is_async();
if (is_async) {
statement = create_async_block(
b.block([
optimiser.apply(),
dynamic && custom_css_props.length === 0
? b.stmt(b.call('$$renderer.push', empty_comment))
: b.empty,
statement
]),
optimiser.blockers(),
optimiser.has_await
);
} else if (dynamic && custom_css_props.length === 0) {
context.state.template.push(empty_comment);
}
context.state.template.push(statement);
context.state.template.push(
...optimiser.render_block([
dynamic && custom_css_props.length === 0
? b.stmt(b.call('$$renderer.push', empty_comment))
: b.empty,
statement
])
);
if (
!is_async &&
!context.state.skip_hydration_boundaries &&
custom_css_props.length === 0 &&
optimiser.expressions.length === 0
) {
if (!optimiser.is_async() && !context.state.is_standalone && custom_css_props.length === 0) {
context.state.template.push(empty_comment);
}
}

@ -81,7 +81,19 @@ export function process_children(nodes, { visit, state }) {
flush();
const expression = /** @type {Expression} */ (visit(node.expression));
state.template.push(create_push(b.call('$.escape', expression), node.metadata.expression));
let call = b.call(
'$$renderer.push',
b.thunk(b.call('$.escape', expression), node.metadata.expression.has_await)
);
const blockers = node.metadata.expression.blockers();
if (blockers.elements.length > 0) {
call = b.call('$$renderer.async', blockers, b.arrow([b.id('$$renderer')], call));
}
state.template.push(b.stmt(call));
} else if (node.type === 'Text' || node.type === 'Comment' || node.type === 'ExpressionTag') {
sequence.push(node);
} else {
@ -262,72 +274,20 @@ export function build_getter(node, state) {
}
/**
* Creates a `$$renderer.child(...)` expression statement
* @param {BlockStatement | Expression} body
* @returns {Statement}
*/
export function create_child_block(body) {
return b.stmt(b.call('$$renderer.child', b.arrow([b.id('$$renderer')], body, true)));
}
/**
* Creates a `$$renderer.async(...)` expression statement
* @param {BlockStatement | Expression} body
* @param {Statement[]} statements
* @param {ArrayExpression} blockers
* @param {boolean} has_await
* @param {boolean} needs_hydration_markers
*/
export function create_async_block(
body,
blockers = b.array([]),
has_await = true,
needs_hydration_markers = true
) {
return b.stmt(
b.call(
needs_hydration_markers ? '$$renderer.async_block' : '$$renderer.async',
blockers,
b.arrow([b.id('$$renderer')], body, has_await)
)
);
}
/**
* @param {Expression} expression
* @param {ExpressionMetadata} metadata
* @param {boolean} needs_hydration_markers
* @returns {Expression | Statement}
*/
export function create_push(expression, metadata, needs_hydration_markers = false) {
if (metadata.is_async()) {
let statement = b.stmt(b.call('$$renderer.push', b.thunk(expression, metadata.has_await)));
const blockers = metadata.blockers();
if (blockers.elements.length > 0) {
statement = create_async_block(
b.block([statement]),
blockers,
false,
needs_hydration_markers
);
}
return statement;
export function create_child_block(statements, blockers, has_await) {
if (blockers.elements.length === 0 && !has_await) {
return statements;
}
return expression;
}
const fn = b.arrow([b.id('$$renderer')], b.block(statements), has_await);
/**
* @param {BlockStatement | Expression} body
* @param {Identifier | false} component_fn_id
* @returns {Statement}
*/
export function call_component_renderer(body, component_fn_id) {
return b.stmt(
b.call('$$renderer.component', b.arrow([b.id('$$renderer')], body, false), component_fn_id)
);
return blockers.elements.length > 0
? [b.stmt(b.call('$$renderer.async_block', blockers, fn))]
: [b.stmt(b.call('$$renderer.child_block', fn))];
}
/**
@ -373,7 +333,7 @@ export class PromiseOptimiser {
}
}
apply() {
#apply() {
if (this.expressions.length === 0) {
return b.empty;
}
@ -403,4 +363,38 @@ export class PromiseOptimiser {
is_async() {
return this.expressions.length > 0 || this.#blockers.size > 0;
}
/**
* @param {Statement[]} statements
* @returns {Statement[]}
*/
render(statements) {
if (!this.is_async()) {
return statements;
}
const fn = b.arrow(
[b.id('$$renderer')],
b.block([this.#apply(), ...statements]),
this.has_await
);
const blockers = this.blockers();
return blockers.elements.length > 0
? [b.stmt(b.call('$$renderer.async', blockers, fn))]
: [b.stmt(b.call('$$renderer.child', fn))];
}
/**
* @param {Statement[]} statements
* @returns {Statement[]}
*/
render_block(statements) {
if (!this.is_async()) {
return statements;
}
return create_child_block([this.#apply(), ...statements], this.blockers(), this.has_await);
}
}

@ -171,6 +171,15 @@ export class Renderer {
return promises;
}
/**
* @param {(renderer: Renderer) => MaybePromise<void>} fn
*/
child_block(fn) {
this.#out.push(BLOCK_OPEN);
this.child(fn);
this.#out.push(BLOCK_CLOSE);
}
/**
* Create a child renderer. The child renderer inherits the state from the parent,
* but has its own content.

@ -0,0 +1,4 @@
<script>
let { children } = $props()
</script>
<div>{@render children?.()}</div>

@ -0,0 +1,4 @@
<script>
let { children } = $props()
</script>
<div>{@render children?.()}</div>

@ -0,0 +1,7 @@
<script lang='ts'>
import type { Attachment } from 'svelte/attachments'
export function action(): Attachment<HTMLElement> {
return ()=>{}
}
</script>

@ -0,0 +1,10 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
mode: ['hydrate'],
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, '<div><div>foo</div></div>');
}
});

@ -0,0 +1,16 @@
<script>
import Outer from './Outer.svelte'
import Inner from './Inner.svelte'
import Trigger from './Trigger.svelte'
const data = $derived(await Promise.resolve(['a', 'b']))
let trigger = $state()
</script>
<Outer>
<Inner {@attach trigger?.action}>
foo
</Inner>
</Outer>
<Trigger bind:this={trigger} />

@ -0,0 +1,5 @@
<script>
let { message, another } = $props()
</script>
<p>{message}</p>

@ -0,0 +1,14 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
mode: ['hydrate'],
ssrHtml: `<p>item 1</p><p>item 2</p><p>item 3</p>`,
html: `<p>item 1</p><p>item 2</p><p>item 3</p>`,
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, '<p>item 1</p><p>item 2</p><p>item 3</p>');
}
});

@ -0,0 +1,10 @@
<script>
import Component from './Component.svelte'
const messages = await Promise.resolve(["item 1", "item 2", "item 3"])
const another = { test: 'test' }
</script>
{#each messages as message}
<Component {message} {another} />
{/each}

@ -19,11 +19,7 @@ export default function Async_const($$renderer) {
]);
$$renderer.push(`<p>`);
$$renderer.async([promises[1]], ($$renderer) => {
$$renderer.push(() => $.escape(b));
});
$$renderer.async([promises[1]], ($$renderer) => $$renderer.push(() => $.escape(b)));
$$renderer.push(`</p>`);
} else {
$$renderer.push('<!--[!-->');

@ -2,7 +2,7 @@ import 'svelte/internal/flags/async';
import * as $ from 'svelte/internal/server';
export default function Async_each_fallback_hoisting($$renderer) {
$$renderer.async_block([], async ($$renderer) => {
$$renderer.child_block(async ($$renderer) => {
const each_array = $.ensure_array_like((await $.save(Promise.resolve([])))());
if (each_array.length !== 0) {

@ -8,7 +8,7 @@ export default function Async_each_hoisting($$renderer) {
$$renderer.push(`<!--[-->`);
$$renderer.async_block([], async ($$renderer) => {
$$renderer.child_block(async ($$renderer) => {
const each_array = $.ensure_array_like((await $.save(Promise.resolve([first, second, third])))());
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {

@ -2,7 +2,7 @@ import 'svelte/internal/flags/async';
import * as $ from 'svelte/internal/server';
export default function Async_if_alternate_hoisting($$renderer) {
$$renderer.async_block([], async ($$renderer) => {
$$renderer.child_block(async ($$renderer) => {
if ((await $.save(Promise.resolve(false)))()) {
$$renderer.push('<!--[-->');
$$renderer.push(async () => $.escape(await Promise.reject('no no no')));

@ -2,7 +2,7 @@ import 'svelte/internal/flags/async';
import * as $ from 'svelte/internal/server';
export default function Async_if_hoisting($$renderer) {
$$renderer.async_block([], async ($$renderer) => {
$$renderer.child_block(async ($$renderer) => {
if ((await $.save(Promise.resolve(true)))()) {
$$renderer.push('<!--[-->');
$$renderer.push(async () => $.escape(await Promise.resolve('yes yes yes')));

@ -6,10 +6,6 @@ export default function Async_top_level_inspect_server($$renderer) {
var $$promises = $$renderer.run([async () => data = await Promise.resolve(42),,]);
$$renderer.push(`<p>`);
$$renderer.async([$$promises[1]], ($$renderer) => {
$$renderer.push(() => $.escape(data));
});
$$renderer.async([$$promises[1]], ($$renderer) => $$renderer.push(() => $.escape(data)));
$$renderer.push(`</p>`);
}
Loading…
Cancel
Save