Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-cooks-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: check boundary `pending` attribute at runtime on server
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
block_open,
block_open_else,
build_attribute_value,
build_template,
create_async_block
} from './shared/utils.js';

Expand All @@ -19,6 +20,11 @@ export function SvelteBoundary(node, context) {
const pending_attribute = /** @type {AST.Attribute} */ (
node.attributes.find((node) => node.type === 'Attribute' && node.name === 'pending')
);
const is_pending_attr_nullish =
pending_attribute &&
typeof pending_attribute.value === 'object' &&
!Array.isArray(pending_attribute.value) &&
!context.state.scope.evaluate(pending_attribute.value.expression).is_defined;

const pending_snippet = /** @type {AST.SnippetBlock} */ (
node.fragment.nodes.find(
Expand All @@ -27,20 +33,38 @@ export function SvelteBoundary(node, context) {
);

if (pending_attribute || pending_snippet) {
const pending = pending_attribute
? b.call(
build_attribute_value(
pending_attribute.value,
context,
(expression) => expression,
false,
true
),
b.id('$$renderer')
if (pending_attribute && is_pending_attr_nullish && !pending_snippet) {
const callee = build_attribute_value(
pending_attribute.value,
context,
(expression) => expression,
false,
true
);
const pending = b.call(callee, b.id('$$renderer'));
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
context.state.template.push(
b.if(
callee,
b.block(build_template([block_open_else, pending, block_close])),
b.block(build_template([block_open, block, block_close]))
)
: /** @type {BlockStatement} */ (context.visit(pending_snippet.body));

context.state.template.push(block_open_else, pending, block_close);
);
} else {
const pending = pending_attribute
? b.call(
build_attribute_value(
pending_attribute.value,
context,
(expression) => expression,
false,
true
),
b.id('$$renderer')
)
: /** @type {BlockStatement} */ (context.visit(pending_snippet.body));
context.state.template.push(block_open_else, pending, block_close);
}
} else {
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
const statement = node.fragment.metadata.has_await
Expand Down
6 changes: 6 additions & 0 deletions packages/svelte/src/compiler/phases/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ class Evaluation {
break;
}

if (binding.initial?.type === 'SnippetBlock') {
this.is_defined = true;
this.is_known = false;
break;
}

if (!binding.updated && binding.initial !== null && !is_prop) {
binding.scope.evaluate(/** @type {Expression} */ (binding.initial), this.values);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!--[--><!--[--><!---->awaited<!--]--><!--]-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<script>
let pending = null;
</script>
<svelte:boundary {pending}>
{await 'awaited'}
</svelte:boundary>
Loading