Skip to content

Commit cfba900

Browse files
committed
represent main/pending/failed effects separately, as we do for other blocks
1 parent 036001c commit cfba900

File tree

1 file changed

+54
-36
lines changed
  • packages/svelte/src/internal/client/dom/blocks

1 file changed

+54
-36
lines changed

packages/svelte/src/internal/client/dom/blocks/boundary.js

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const ASYNC_DECREMENT = Symbol();
3535

3636
/**
3737
* @param {Effect} boundary
38-
* @param {() => void} fn
38+
* @param {() => Effect | null} fn
39+
* @returns {Effect | null}
3940
*/
4041
function with_boundary(boundary, fn) {
4142
var previous_effect = active_effect;
@@ -47,7 +48,7 @@ function with_boundary(boundary, fn) {
4748
set_component_context(boundary.ctx);
4849

4950
try {
50-
fn();
51+
return fn();
5152
} finally {
5253
set_active_effect(previous_effect);
5354
set_active_reaction(previous_reaction);
@@ -69,11 +70,14 @@ export function boundary(node, props, children) {
6970
var anchor = node;
7071

7172
block(() => {
72-
/** @type {Effect} */
73-
var boundary_effect;
73+
/** @type {Effect | null} */
74+
var main_effect = null;
75+
76+
/** @type {Effect | null} */
77+
var pending_effect = null;
7478

7579
/** @type {Effect | null} */
76-
var offscreen_effect = null;
80+
var failed_effect = null;
7781

7882
/** @type {DocumentFragment | null} */
7983
var offscreen_fragment = null;
@@ -85,32 +89,33 @@ export function boundary(node, props, children) {
8589

8690
/**
8791
* @param {() => void} snippet_fn
92+
* @returns {Effect | null}
8893
*/
8994
function render_snippet(snippet_fn) {
90-
with_boundary(boundary, () => {
95+
return with_boundary(boundary, () => {
9196
is_creating_fallback = true;
9297

9398
try {
94-
boundary_effect = branch(snippet_fn);
99+
return branch(snippet_fn);
95100
} catch (error) {
96101
handle_error(error, boundary, null, boundary.ctx);
102+
return null;
103+
} finally {
104+
reset_is_throwing_error();
105+
is_creating_fallback = false;
97106
}
98-
99-
reset_is_throwing_error();
100-
is_creating_fallback = false;
101107
});
102108
}
103109

104110
function suspend() {
105-
if (offscreen_effect || !boundary_effect) {
111+
if (offscreen_fragment || !main_effect) {
106112
return;
107113
}
108114

109-
var effect = boundary_effect;
110-
offscreen_effect = boundary_effect;
115+
var effect = main_effect;
111116

112117
pause_effect(
113-
boundary_effect,
118+
effect,
114119
() => {
115120
var node = effect.nodes_start;
116121
var end = effect.nodes_end;
@@ -131,34 +136,40 @@ export function boundary(node, props, children) {
131136
const pending = props.pending;
132137

133138
if (pending) {
134-
render_snippet(() => {
135-
pending(anchor);
136-
});
139+
pending_effect = render_snippet(() => pending(anchor));
137140
}
138141
}
139142

140143
function unsuspend() {
141-
if (!offscreen_effect) {
144+
if (!offscreen_fragment) {
142145
return;
143146
}
144147

145-
if (boundary_effect) {
146-
destroy_effect(boundary_effect);
148+
if (pending_effect !== null) {
149+
pause_effect(pending_effect);
147150
}
148151

149-
boundary_effect = offscreen_effect;
150-
offscreen_effect = null;
151152
anchor.before(/** @type {DocumentFragment} */ (offscreen_fragment));
152-
resume_effect(boundary_effect);
153+
offscreen_fragment = null;
154+
155+
if (main_effect !== null) {
156+
resume_effect(main_effect);
157+
}
153158
}
154159

155160
function reset() {
156-
pause_effect(boundary_effect);
161+
if (failed_effect !== null) {
162+
pause_effect(failed_effect);
163+
}
157164

158-
with_boundary(boundary, () => {
165+
main_effect = with_boundary(boundary, () => {
159166
is_creating_fallback = false;
160-
boundary_effect = branch(() => children(anchor));
161-
reset_is_throwing_error();
167+
168+
try {
169+
return branch(() => children(anchor));
170+
} finally {
171+
reset_is_throwing_error();
172+
}
162173
});
163174
}
164175

@@ -192,17 +203,23 @@ export function boundary(node, props, children) {
192203

193204
onerror?.(error, reset);
194205

195-
if (boundary_effect) {
196-
destroy_effect(boundary_effect);
197-
} else if (hydrating) {
206+
if (main_effect) {
207+
destroy_effect(main_effect);
208+
}
209+
210+
if (failed_effect) {
211+
destroy_effect(failed_effect);
212+
}
213+
214+
if (hydrating) {
198215
set_hydrate_node(hydrate_open);
199216
next();
200217
set_hydrate_node(remove_nodes());
201218
}
202219

203220
if (failed) {
204221
queue_boundary_micro_task(() => {
205-
render_snippet(() => {
222+
failed_effect = render_snippet(() => {
206223
failed(
207224
anchor,
208225
() => error,
@@ -223,7 +240,7 @@ export function boundary(node, props, children) {
223240
const pending = props.pending;
224241

225242
if (hydrating && pending) {
226-
boundary_effect = branch(() => pending(anchor));
243+
pending_effect = branch(() => pending(anchor));
227244

228245
// ...now what? we need to start rendering `boundary_fn` offscreen,
229246
// and either insert the resulting fragment (if nothing suspends)
@@ -235,13 +252,14 @@ export function boundary(node, props, children) {
235252
// the pending or main block was rendered for a given
236253
// boundary, and hydrate accordingly
237254
queueMicrotask(() => {
238-
destroy_effect(boundary_effect);
239-
with_boundary(boundary, () => {
240-
boundary_effect = branch(() => children(anchor));
255+
destroy_effect(/** @type {Effect} */ (pending_effect));
256+
257+
main_effect = with_boundary(boundary, () => {
258+
return branch(() => children(anchor));
241259
});
242260
});
243261
} else {
244-
boundary_effect = branch(() => children(anchor));
262+
main_effect = branch(() => children(anchor));
245263
}
246264

247265
reset_is_throwing_error();

0 commit comments

Comments
 (0)