Skip to content

Commit 41e7dab

Browse files
authored
chore: move block logic into separate modules (#10542)
* move if block logic * key and await * move each * move more stuff * dedupe --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 71db9ed commit 41e7dab

File tree

8 files changed

+644
-604
lines changed

8 files changed

+644
-604
lines changed

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

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -32,48 +32,6 @@ export function create_root_block(intro) {
3232
};
3333
}
3434

35-
/** @returns {import('./types.js').IfBlock} */
36-
export function create_if_block() {
37-
return {
38-
// alternate transitions
39-
a: null,
40-
// alternate effect
41-
ae: null,
42-
// consequent transitions
43-
c: null,
44-
// consequent effect
45-
ce: null,
46-
// dom
47-
d: null,
48-
// effect
49-
e: null,
50-
// parent
51-
p: /** @type {import('./types.js').Block} */ (current_block),
52-
// transition
53-
r: null,
54-
// type
55-
t: IF_BLOCK,
56-
// value
57-
v: false
58-
};
59-
}
60-
61-
/** @returns {import('./types.js').KeyBlock} */
62-
export function create_key_block() {
63-
return {
64-
// dom
65-
d: null,
66-
// effect
67-
e: null,
68-
// parent
69-
p: /** @type {import('./types.js').Block} */ (current_block),
70-
// transition
71-
r: null,
72-
// type
73-
t: KEY_BLOCK
74-
};
75-
}
76-
7735
/** @returns {import('./types.js').HeadBlock} */
7836
export function create_head_block() {
7937
return {
@@ -122,82 +80,6 @@ export function create_dynamic_component_block() {
12280
};
12381
}
12482

125-
/** @returns {import('./types.js').AwaitBlock} */
126-
export function create_await_block() {
127-
return {
128-
// dom
129-
d: null,
130-
// effect
131-
e: null,
132-
// parent
133-
p: /** @type {import('./types.js').Block} */ (current_block),
134-
// pending
135-
n: true,
136-
// transition
137-
r: null,
138-
// type
139-
t: AWAIT_BLOCK
140-
};
141-
}
142-
143-
/**
144-
* @param {number} flags
145-
* @param {Element | Comment} anchor
146-
* @returns {import('./types.js').EachBlock}
147-
*/
148-
export function create_each_block(flags, anchor) {
149-
return {
150-
// anchor
151-
a: anchor,
152-
// dom
153-
d: null,
154-
// flags
155-
f: flags,
156-
// items
157-
v: [],
158-
// effect
159-
e: null,
160-
p: /** @type {import('./types.js').Block} */ (current_block),
161-
// transition
162-
r: null,
163-
// transitions
164-
s: [],
165-
// type
166-
t: EACH_BLOCK
167-
};
168-
}
169-
170-
/**
171-
* @param {any | import('./types.js').Signal<any>} item
172-
* @param {number | import('./types.js').Signal<number>} index
173-
* @param {null | unknown} key
174-
* @returns {import('./types.js').EachItemBlock}
175-
*/
176-
export function create_each_item_block(item, index, key) {
177-
return {
178-
// animate transition
179-
a: null,
180-
// dom
181-
d: null,
182-
// effect
183-
e: null,
184-
// index
185-
i: index,
186-
// key
187-
k: key,
188-
// item
189-
v: item,
190-
// parent
191-
p: /** @type {import('./types.js').EachBlock} */ (current_block),
192-
// transition
193-
r: null,
194-
// transitions
195-
s: null,
196-
// type
197-
t: EACH_ITEM_BLOCK
198-
};
199-
}
200-
20183
/** @returns {import('./types.js').SnippetBlock} */
20284
export function create_snippet_block() {
20385
return {
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import { is_promise } from '../../../common.js';
2+
import { AWAIT_BLOCK } from '../../block.js';
3+
import { hydrate_block_anchor } from '../../hydration.js';
4+
import { remove } from '../../reconciler.js';
5+
import {
6+
UNINITIALIZED,
7+
current_block,
8+
destroy_signal,
9+
execute_effect,
10+
flushSync,
11+
push_destroy_fn,
12+
render_effect
13+
} from '../../runtime.js';
14+
import { trigger_transitions } from '../../transitions.js';
15+
16+
/** @returns {import('../../types.js').AwaitBlock} */
17+
export function create_await_block() {
18+
return {
19+
// dom
20+
d: null,
21+
// effect
22+
e: null,
23+
// parent
24+
p: /** @type {import('../../types.js').Block} */ (current_block),
25+
// pending
26+
n: true,
27+
// transition
28+
r: null,
29+
// type
30+
t: AWAIT_BLOCK
31+
};
32+
}
33+
34+
/**
35+
* @template V
36+
* @param {Comment} anchor_node
37+
* @param {(() => Promise<V>)} input
38+
* @param {null | ((anchor: Node) => void)} pending_fn
39+
* @param {null | ((anchor: Node, value: V) => void)} then_fn
40+
* @param {null | ((anchor: Node, error: unknown) => void)} catch_fn
41+
* @returns {void}
42+
*/
43+
export function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
44+
const block = create_await_block();
45+
46+
/** @type {null | import('../../types.js').Render} */
47+
let current_render = null;
48+
hydrate_block_anchor(anchor_node);
49+
50+
/** @type {{}} */
51+
let latest_token;
52+
53+
/** @type {typeof UNINITIALIZED | V} */
54+
let resolved_value = UNINITIALIZED;
55+
56+
/** @type {unknown} */
57+
let error = UNINITIALIZED;
58+
let pending = false;
59+
block.r =
60+
/**
61+
* @param {import('../../types.js').Transition} transition
62+
* @returns {void}
63+
*/
64+
(transition) => {
65+
const render = /** @type {import('../../types.js').Render} */ (current_render);
66+
const transitions = render.s;
67+
transitions.add(transition);
68+
transition.f(() => {
69+
transitions.delete(transition);
70+
if (transitions.size === 0) {
71+
// If the current render has changed since, then we can remove the old render
72+
// effect as it's stale.
73+
if (current_render !== render && render.e !== null) {
74+
if (render.d !== null) {
75+
remove(render.d);
76+
render.d = null;
77+
}
78+
destroy_signal(render.e);
79+
render.e = null;
80+
}
81+
}
82+
});
83+
};
84+
const create_render_effect = () => {
85+
/** @type {import('../../types.js').Render} */
86+
const render = {
87+
d: null,
88+
e: null,
89+
s: new Set(),
90+
p: current_render
91+
};
92+
const effect = render_effect(
93+
() => {
94+
if (error === UNINITIALIZED) {
95+
if (resolved_value === UNINITIALIZED) {
96+
// pending = true
97+
block.n = true;
98+
if (pending_fn !== null) {
99+
pending_fn(anchor_node);
100+
}
101+
} else if (then_fn !== null) {
102+
// pending = false
103+
block.n = false;
104+
then_fn(anchor_node, resolved_value);
105+
}
106+
} else if (catch_fn !== null) {
107+
// pending = false
108+
block.n = false;
109+
catch_fn(anchor_node, error);
110+
}
111+
render.d = block.d;
112+
block.d = null;
113+
},
114+
block,
115+
true,
116+
true
117+
);
118+
render.e = effect;
119+
current_render = render;
120+
};
121+
const render = () => {
122+
const render = current_render;
123+
if (render === null) {
124+
create_render_effect();
125+
return;
126+
}
127+
const transitions = render.s;
128+
if (transitions.size === 0) {
129+
if (render.d !== null) {
130+
remove(render.d);
131+
render.d = null;
132+
}
133+
if (render.e) {
134+
execute_effect(render.e);
135+
} else {
136+
create_render_effect();
137+
}
138+
} else {
139+
create_render_effect();
140+
trigger_transitions(transitions, 'out');
141+
}
142+
};
143+
const await_effect = render_effect(
144+
() => {
145+
const token = {};
146+
latest_token = token;
147+
const promise = input();
148+
if (is_promise(promise)) {
149+
promise.then(
150+
/** @param {V} v */
151+
(v) => {
152+
if (latest_token === token) {
153+
// Ensure UI is in sync before resolving value.
154+
flushSync();
155+
resolved_value = v;
156+
pending = false;
157+
render();
158+
}
159+
},
160+
/** @param {unknown} _error */
161+
(_error) => {
162+
error = _error;
163+
pending = false;
164+
render();
165+
}
166+
);
167+
if (resolved_value !== UNINITIALIZED || error !== UNINITIALIZED) {
168+
error = UNINITIALIZED;
169+
resolved_value = UNINITIALIZED;
170+
}
171+
if (!pending) {
172+
pending = true;
173+
render();
174+
}
175+
} else {
176+
error = UNINITIALIZED;
177+
resolved_value = promise;
178+
pending = false;
179+
render();
180+
}
181+
},
182+
block,
183+
false
184+
);
185+
push_destroy_fn(await_effect, () => {
186+
let render = current_render;
187+
latest_token = {};
188+
while (render !== null) {
189+
const dom = render.d;
190+
if (dom !== null) {
191+
remove(dom);
192+
}
193+
const effect = render.e;
194+
if (effect !== null) {
195+
destroy_signal(effect);
196+
}
197+
render = render.p;
198+
}
199+
});
200+
block.e = await_effect;
201+
}

0 commit comments

Comments
 (0)