Skip to content

Commit 41314a6

Browse files
committed
WIP
1 parent 2b08128 commit 41314a6

File tree

4 files changed

+98
-75
lines changed

4 files changed

+98
-75
lines changed

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

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import * as e from '../../../shared/errors.js';
3333

3434
const ASYNC_INCREMENT = Symbol();
3535
const ASYNC_DECREMENT = Symbol();
36+
const ADD_CALLBACK = Symbol();
3637

3738
/**
3839
* @param {Effect} boundary
@@ -88,6 +89,9 @@ export function boundary(node, props, children) {
8889
var hydrate_open = hydrate_node;
8990
var is_creating_fallback = false;
9091

92+
/** @type {Function[]} */
93+
var callbacks = [];
94+
9195
/**
9296
* @param {() => void} snippet_fn
9397
* @returns {Effect | null}
@@ -108,48 +112,6 @@ export function boundary(node, props, children) {
108112
});
109113
}
110114

111-
function suspend() {
112-
if (offscreen_fragment || !main_effect) {
113-
return;
114-
}
115-
116-
var effect = main_effect;
117-
118-
pause_effect(
119-
effect,
120-
() => {
121-
offscreen_fragment = document.createDocumentFragment();
122-
move_effect(effect, offscreen_fragment);
123-
},
124-
false
125-
);
126-
127-
const pending = props.pending;
128-
129-
if (pending) {
130-
pending_effect = render_snippet(() => pending(anchor));
131-
}
132-
}
133-
134-
function unsuspend() {
135-
if (!offscreen_fragment) {
136-
return;
137-
}
138-
139-
if (pending_effect !== null) {
140-
pause_effect(pending_effect, () => {
141-
pending_effect = null;
142-
});
143-
}
144-
145-
anchor.before(/** @type {DocumentFragment} */ (offscreen_fragment));
146-
offscreen_fragment = null;
147-
148-
if (main_effect !== null) {
149-
resume_effect(main_effect);
150-
}
151-
}
152-
153115
function reset() {
154116
if (failed_effect !== null) {
155117
pause_effect(failed_effect, () => {
@@ -169,7 +131,7 @@ export function boundary(node, props, children) {
169131
}
170132

171133
// @ts-ignore We re-use the effect's fn property to avoid allocation of an additional field
172-
boundary.fn = (/** @type {unknown} */ input) => {
134+
boundary.fn = (/** @type {unknown} */ input, /** @type {Function} */ payload) => {
173135
if (input === ASYNC_INCREMENT) {
174136
async_count++;
175137

@@ -182,6 +144,12 @@ export function boundary(node, props, children) {
182144
if (--async_count === 0) {
183145
boundary.f ^= BOUNDARY_SUSPENDED;
184146

147+
for (const callback of callbacks) {
148+
callback();
149+
}
150+
151+
callbacks.length = 0;
152+
185153
if (pending_effect) {
186154
pause_effect(pending_effect, () => {
187155
pending_effect = null;
@@ -202,6 +170,11 @@ export function boundary(node, props, children) {
202170
return;
203171
}
204172

173+
if (input === ADD_CALLBACK) {
174+
callbacks.push(payload);
175+
return;
176+
}
177+
205178
var error = input;
206179
var onerror = props.onerror;
207180
let failed = props.failed;
@@ -377,3 +350,27 @@ function exit() {
377350
set_active_reaction(null);
378351
set_component_context(null);
379352
}
353+
354+
/**
355+
* @param {Effect | null} effect
356+
*/
357+
export function find_boundary(effect) {
358+
while (effect !== null && (effect.f & BOUNDARY_EFFECT) === 0) {
359+
effect = effect.parent;
360+
}
361+
362+
return effect;
363+
}
364+
365+
/**
366+
* @param {Effect | null} boundary
367+
* @param {Function} fn
368+
*/
369+
export function add_boundary_callback(boundary, fn) {
370+
if (boundary === null) {
371+
throw new Error('TODO');
372+
}
373+
374+
// @ts-ignore
375+
boundary.fn(ADD_CALLBACK, fn);
376+
}

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

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
} from '../hydration.js';
1111
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
1212
import { HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js';
13+
import { active_effect, suspended } from '../../runtime.js';
14+
import { add_boundary_callback, find_boundary } from './boundary.js';
1315

1416
/**
1517
* @param {TemplateNode} node
@@ -42,6 +44,46 @@ export function if_block(node, fn, elseif = false) {
4244
update_branch(flag, fn);
4345
};
4446

47+
/** @type {DocumentFragment | null} */
48+
var offscreen_fragment = null;
49+
50+
/** @type {Effect | null} */
51+
var pending_effect = null;
52+
53+
var boundary = find_boundary(active_effect);
54+
55+
function commit() {
56+
if (offscreen_fragment !== null) {
57+
anchor.before(offscreen_fragment);
58+
offscreen_fragment = null;
59+
}
60+
61+
if (condition) {
62+
consequent_effect = pending_effect;
63+
} else {
64+
alternate_effect = pending_effect;
65+
}
66+
67+
var current_effect = condition ? consequent_effect : alternate_effect;
68+
var previous_effect = condition ? alternate_effect : consequent_effect;
69+
70+
if (current_effect !== null) {
71+
resume_effect(current_effect);
72+
}
73+
74+
if (previous_effect !== null) {
75+
pause_effect(previous_effect, () => {
76+
if (condition) {
77+
alternate_effect = null;
78+
} else {
79+
consequent_effect = null;
80+
}
81+
});
82+
}
83+
84+
pending_effect = null;
85+
}
86+
4587
const update_branch = (
4688
/** @type {boolean | null} */ new_condition,
4789
/** @type {null | ((anchor: Node) => void)} */ fn
@@ -65,30 +107,19 @@ export function if_block(node, fn, elseif = false) {
65107
}
66108
}
67109

68-
if (condition) {
69-
if (consequent_effect) {
70-
resume_effect(consequent_effect);
71-
} else if (fn) {
72-
consequent_effect = branch(() => fn(anchor));
73-
}
110+
var target = anchor;
74111

75-
if (alternate_effect) {
76-
pause_effect(alternate_effect, () => {
77-
alternate_effect = null;
78-
});
79-
}
80-
} else {
81-
if (alternate_effect) {
82-
resume_effect(alternate_effect);
83-
} else if (fn) {
84-
alternate_effect = branch(() => fn(anchor));
85-
}
112+
if (suspended) {
113+
offscreen_fragment = document.createDocumentFragment();
114+
offscreen_fragment.append((target = document.createComment('')));
115+
}
86116

87-
if (consequent_effect) {
88-
pause_effect(consequent_effect, () => {
89-
consequent_effect = null;
90-
});
91-
}
117+
pending_effect = fn && branch(() => fn(target));
118+
119+
if (suspended) {
120+
add_boundary_callback(boundary, commit);
121+
} else {
122+
commit();
92123
}
93124

94125
if (mismatch) {

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -567,20 +567,15 @@ export function unlink_effect(effect) {
567567
* A paused effect does not update, and the DOM subtree becomes inert.
568568
* @param {Effect} effect
569569
* @param {() => void} [callback]
570-
* @param {boolean} [destroy]
571570
*/
572-
export function pause_effect(effect, callback, destroy = true) {
571+
export function pause_effect(effect, callback) {
573572
/** @type {TransitionManager[]} */
574573
var transitions = [];
575574

576575
pause_children(effect, transitions, true);
577576

578577
run_out_transitions(transitions, () => {
579-
if (destroy) {
580-
destroy_effect(effect);
581-
} else {
582-
execute_effect_teardown(effect);
583-
}
578+
destroy_effect(effect);
584579
if (callback) callback();
585580
});
586581
}

packages/svelte/src/internal/client/runtime.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
DISCONNECTED,
2828
BOUNDARY_EFFECT,
2929
REACTION_IS_UPDATING,
30-
IS_ASYNC,
3130
TEMPLATE_EFFECT,
3231
BOUNDARY_SUSPENDED
3332
} from './constants.js';
@@ -44,7 +43,6 @@ import { lifecycle_outside_component } from '../shared/errors.js';
4443
import { FILENAME } from '../../constants.js';
4544
import { legacy_mode_flag, tracing_mode_flag } from '../flags/index.js';
4645
import { tracing_expressions, get_stack } from './dev/tracing.js';
47-
import { is_pending_boundary } from './dom/blocks/boundary.js';
4846

4947
const FLUSH_MICROTASK = 0;
5048
const FLUSH_SYNC = 1;
@@ -89,6 +87,8 @@ export let active_reaction = null;
8987

9088
export let untracking = false;
9189

90+
export let suspended = false;
91+
9292
/** @param {null | Reaction} reaction */
9393
export function set_active_reaction(reaction) {
9494
active_reaction = reaction;
@@ -826,7 +826,7 @@ export function schedule_effect(signal) {
826826
function process_effects(effect, collected_effects) {
827827
var current_effect = effect.first;
828828
var effects = [];
829-
var suspended = false;
829+
suspended = false;
830830

831831
main_loop: while (current_effect !== null) {
832832
var flags = current_effect.f;

0 commit comments

Comments
 (0)