Skip to content

Commit 53a95a1

Browse files
committed
WIP
1 parent 3ce74e4 commit 53a95a1

File tree

12 files changed

+73
-165
lines changed

12 files changed

+73
-165
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { is_promise } from '../../../common.js';
2-
import { hydrate_block_anchor } from '../hydration.js';
32
import { remove } from '../reconciler.js';
43
import {
54
current_component_context,
@@ -23,8 +22,6 @@ import { INERT } from '../../constants.js';
2322
export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
2423
const component_context = current_component_context;
2524

26-
hydrate_block_anchor(anchor);
27-
2825
/** @type {any} */
2926
let input;
3027

packages/svelte/src/internal/client/dom/blocks/css-props.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { namespace_svg } from '../../../../constants.js';
2-
import { hydrate_nodes, hydrate_block_anchor, hydrating } from '../hydration.js';
2+
import { hydrate_nodes, hydrating } from '../hydration.js';
33
import { empty } from '../operations.js';
44
import { render_effect } from '../../reactivity/effects.js';
55
import { remove } from '../reconciler.js';
@@ -12,8 +12,6 @@ import { remove } from '../reconciler.js';
1212
* @returns {void}
1313
*/
1414
export function css_props(anchor, is_html, props, component) {
15-
hydrate_block_anchor(anchor);
16-
1715
/** @type {HTMLElement | SVGElement} */
1816
let element;
1917

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

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
EACH_KEYED
88
} from '../../../../constants.js';
99
import {
10+
hydrate_anchor,
1011
hydrate_nodes,
11-
hydrate_block_anchor,
1212
hydrating,
1313
set_hydrating,
1414
update_hydrate_nodes
@@ -59,11 +59,13 @@ function each(anchor, flags, get_collection, get_key, render_fn, fallback_fn, re
5959
var state = { flags, items: [] };
6060

6161
var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
62-
hydrate_block_anchor(is_controlled ? /** @type {Node} */ (anchor.firstChild) : anchor);
6362

6463
if (is_controlled) {
6564
var parent_node = /** @type {Element} */ (anchor);
66-
parent_node.append((anchor = empty()));
65+
66+
anchor = /** @type {Comment | Text} */ (
67+
hydrate_anchor(parent_node.firstChild ?? parent_node.appendChild(empty()))
68+
);
6769
}
6870

6971
/** @type {import('#client').Effect | null} */
@@ -115,32 +117,29 @@ function each(anchor, flags, get_collection, get_key, render_fn, fallback_fn, re
115117
if (hydrating) {
116118
var b_items = [];
117119

118-
// Hydrate block
119-
var hydration_list = /** @type {import('#client').TemplateNode[]} */ (hydrate_nodes);
120-
var hydrating_node = hydration_list[0];
120+
/** @type {Node} */
121+
var child_anchor = hydrate_nodes[0];
121122

122123
for (var i = 0; i < length; i++) {
123-
var nodes = update_hydrate_nodes(hydrating_node);
124-
125-
if (nodes === null) {
124+
if (child_anchor.nodeType !== 8 || /** @type {Comment} */ (child_anchor).data !== '[') {
126125
// If `nodes` is null, then that means that the server rendered fewer items than what
127126
// expected, so break out and continue appending non-hydrated items
128127
mismatch = true;
129128
set_hydrating(false);
130129
break;
131130
}
132131

132+
child_anchor = hydrate_anchor(child_anchor);
133133
b_items[i] = create_item(array[i], keys?.[i], i, render_fn, flags);
134-
135-
// TODO helperise this
136-
hydrating_node = /** @type {import('#client').TemplateNode} */ (
137-
/** @type {Node} */ (
138-
/** @type {Node} */ (nodes[nodes.length - 1] || hydrating_node).nextSibling
139-
).nextSibling
140-
);
134+
child_anchor = /** @type {Comment} */ (child_anchor.nextSibling);
141135
}
142136

143-
remove_excess_hydration_nodes(hydration_list, hydrating_node);
137+
// remove excess nodes
138+
while (child_anchor !== anchor) {
139+
var next = /** @type {import('#client').TemplateNode} */ (child_anchor.nextSibling);
140+
/** @type {import('#client').TemplateNode} */ (child_anchor).remove();
141+
child_anchor = next;
142+
}
144143

145144
state.items = b_items;
146145
}
@@ -440,20 +439,6 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) {
440439
});
441440
}
442441

443-
/**
444-
* The server could have rendered more list items than the client specifies.
445-
* In that case, we need to remove the remaining server-rendered nodes.
446-
* @param {import('#client').TemplateNode[]} hydration_list
447-
* @param {import('#client').TemplateNode | null} next_node
448-
*/
449-
function remove_excess_hydration_nodes(hydration_list, next_node) {
450-
if (next_node === null) return;
451-
var idx = hydration_list.indexOf(next_node);
452-
if (idx !== -1 && hydration_list.length > idx + 1) {
453-
remove(hydration_list.slice(idx));
454-
}
455-
}
456-
457442
/**
458443
* Longest Increased Subsequence algorithm
459444
* @param {Int32Array} a

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IS_ELSEIF } from '../../constants.js';
2-
import { hydrate_nodes, hydrate_block_anchor, hydrating, set_hydrating } from '../hydration.js';
2+
import { hydrate_nodes, hydrating, set_hydrating } from '../hydration.js';
33
import { remove } from '../reconciler.js';
44
import {
55
destroy_effect,
@@ -23,8 +23,6 @@ export function if_block(
2323
alternate_fn = null,
2424
elseif = false
2525
) {
26-
hydrate_block_anchor(anchor);
27-
2826
/** @type {import('#client').Effect | null} */
2927
let consequent_effect = null;
3028

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { UNINITIALIZED } from '../../constants.js';
2-
import { hydrate_block_anchor } from '../hydration.js';
32
import { remove } from '../reconciler.js';
43
import { pause_effect, render_effect } from '../../reactivity/effects.js';
54
import { safe_not_equal } from '../../reactivity/equality.js';
@@ -12,8 +11,6 @@ import { safe_not_equal } from '../../reactivity/equality.js';
1211
* @returns {void}
1312
*/
1413
export function key_block(anchor, get_key, render_fn) {
15-
hydrate_block_anchor(anchor);
16-
1714
/** @type {V | typeof UNINITIALIZED} */
1815
let key = UNINITIALIZED;
1916

packages/svelte/src/internal/client/dom/blocks/svelte-component.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { hydrate_block_anchor } from '../hydration.js';
21
import { pause_effect, render_effect } from '../../reactivity/effects.js';
32
import { remove } from '../reconciler.js';
43
import { current_effect } from '../../runtime.js';
@@ -14,8 +13,6 @@ import { current_effect } from '../../runtime.js';
1413
* @returns {void}
1514
*/
1615
export function component(anchor, get_component, render_fn) {
17-
hydrate_block_anchor(anchor);
18-
1916
/** @type {C} */
2017
let component;
2118

packages/svelte/src/internal/client/dom/blocks/svelte-element.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { namespace_svg } from '../../../../constants.js';
2-
import { hydrate_nodes, hydrate_block_anchor, hydrating } from '../hydration.js';
2+
import { hydrate_nodes, hydrating } from '../hydration.js';
33
import { empty } from '../operations.js';
44
import {
55
destroy_effect,
@@ -44,8 +44,6 @@ function swap_block_dom(effect, from, to) {
4444
export function element(anchor, get_tag, is_svg, render_fn) {
4545
const parent_effect = /** @type {import('#client').Effect} */ (current_effect);
4646

47-
hydrate_block_anchor(anchor);
48-
4947
/** @type {string | null} */
5048
let tag;
5149

packages/svelte/src/internal/client/dom/hydration.js

Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -40,91 +40,43 @@ export function update_hydrate_nodes(first, insert_text) {
4040

4141
/**
4242
* Returns all nodes between the first `<![>...<!]>` comment tag pair encountered.
43-
* @param {Node | null} node
44-
* @param {boolean} [insert_text] Whether to insert an empty text node if `nodes` is empty
45-
* @returns {import('#client').TemplateNode[] | null}
43+
* @param {Node} node
44+
* @returns {Node}
4645
*/
47-
function get_hydrate_nodes(node, insert_text = false) {
48-
/** @type {import('#client').TemplateNode[]} */
49-
var nodes = [];
46+
export function hydrate_anchor(node) {
47+
if (node.nodeType !== 8) {
48+
return node;
49+
}
5050

51-
var current_node = /** @type {null | import('#client').TemplateNode} */ (node);
51+
var current = /** @type {Node | null} */ (node);
5252

53-
var depth = 0;
53+
// TODO this could have false positives, if a user comment consisted of `[`. need to tighten that up
54+
if (/** @type {Comment} */ (current)?.data !== '[') {
55+
return node;
56+
}
5457

55-
var will_start = false;
56-
var started = false;
58+
/** @type {Node[]} */
59+
var nodes = [];
60+
var depth = 0;
5761

58-
while (current_node !== null) {
59-
if (current_node.nodeType === 8) {
60-
var data = /** @type {Comment} */ (current_node).data;
62+
while ((current = /** @type {Node} */ (current).nextSibling) !== null) {
63+
if (current.nodeType === 8) {
64+
var data = /** @type {Comment} */ (current).data;
6165

6266
if (data === '[') {
6367
depth += 1;
64-
will_start = true;
6568
} else if (data === ']') {
66-
if (!started) {
67-
// TODO get rid of this — it exists because each blocks are doubly wrapped
68-
return null;
69+
if (depth === 0) {
70+
hydrate_nodes = /** @type {import('#client').TemplateNode[]} */ (nodes);
71+
return current;
6972
}
7073

71-
if (--depth === 0) {
72-
if (insert_text && nodes.length === 0) {
73-
var text = empty();
74-
nodes.push(text);
75-
current_node.before(text);
76-
}
77-
78-
return nodes;
79-
}
74+
depth -= 1;
8075
}
8176
}
8277

83-
if (started) {
84-
nodes.push(current_node);
85-
}
86-
87-
current_node = /** @type {null | import('#client').TemplateNode} */ (current_node.nextSibling);
88-
89-
started = will_start;
78+
nodes.push(current);
9079
}
9180

92-
return null;
93-
}
94-
95-
/**
96-
* @param {Node} node
97-
* @returns {void}
98-
*/
99-
export function hydrate_block_anchor(node) {
100-
if (!hydrating) return;
101-
102-
// @ts-ignore
103-
var nodes = node.$$fragment ?? get_hydrate_nodes(node);
104-
set_hydrate_nodes(nodes);
105-
}
106-
107-
/**
108-
* Expects to only be called in hydration mode
109-
* @param {Node} node
110-
* @returns {Node}
111-
*/
112-
export function capture_fragment_from_node(node) {
113-
if (
114-
node.nodeType === 8 &&
115-
/** @type {Comment} */ (node).data === '[' &&
116-
hydrate_nodes?.[hydrate_nodes.length - 1] !== node
117-
) {
118-
const nodes = /** @type {Node[]} */ (get_hydrate_nodes(node));
119-
const last_child = nodes[nodes.length - 1] || node;
120-
const target = /** @type {Node} */ (last_child.nextSibling);
121-
// @ts-ignore
122-
target.$$fragment = nodes;
123-
schedule_task(() => {
124-
// @ts-expect-error clean up memory
125-
target.$$fragment = undefined;
126-
});
127-
return target;
128-
}
129-
return node;
81+
throw new Error('Expected a closing hydration marker');
13082
}

packages/svelte/src/internal/client/dom/operations.js

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { capture_fragment_from_node, hydrate_nodes, hydrating } from './hydration.js';
1+
import { hydrate_anchor, hydrate_nodes, hydrating } from './hydration.js';
22
import { get_descriptor } from '../utils.js';
33

44
// We cache the Node and Element prototype methods, so that we can avoid doing
@@ -132,7 +132,7 @@ export function child(node) {
132132
return node.appendChild(empty());
133133
}
134134

135-
return capture_fragment_from_node(child);
135+
return hydrate_anchor(child);
136136
}
137137

138138
/**
@@ -159,11 +159,7 @@ export function first_child(fragment, is_text) {
159159
return text;
160160
}
161161

162-
if (first_node !== null) {
163-
return capture_fragment_from_node(first_node);
164-
}
165-
166-
return first_node;
162+
return hydrate_anchor(first_node);
167163
}
168164

169165
/**
@@ -176,28 +172,26 @@ export function first_child(fragment, is_text) {
176172
export function sibling(node, is_text = false) {
177173
const next_sibling = next_sibling_get.call(node);
178174

179-
if (hydrating) {
180-
// if a sibling {expression} is empty during SSR, there might be no
181-
// text node to hydrate — we must therefore create one
182-
if (is_text && next_sibling?.nodeType !== 3) {
183-
const text = empty();
184-
if (next_sibling) {
185-
const index = hydrate_nodes.indexOf(/** @type {Text | Comment | Element} */ (next_sibling));
186-
hydrate_nodes.splice(index, 0, text);
187-
next_sibling.before(text);
188-
} else {
189-
hydrate_nodes.push(text);
190-
}
191-
192-
return text;
193-
}
175+
if (!hydrating) {
176+
return next_sibling;
177+
}
194178

195-
if (next_sibling !== null) {
196-
return capture_fragment_from_node(next_sibling);
179+
// if a sibling {expression} is empty during SSR, there might be no
180+
// text node to hydrate — we must therefore create one
181+
if (is_text && next_sibling?.nodeType !== 3) {
182+
const text = empty();
183+
if (next_sibling) {
184+
const index = hydrate_nodes.indexOf(/** @type {Text | Comment | Element} */ (next_sibling));
185+
hydrate_nodes.splice(index, 0, text);
186+
next_sibling.before(text);
187+
} else {
188+
hydrate_nodes.push(text);
197189
}
190+
191+
return text;
198192
}
199193

200-
return next_sibling;
194+
return hydrate_anchor(/** @type {Node} */ (next_sibling));
201195
}
202196

203197
/**

packages/svelte/src/internal/client/dom/reconciler.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { append_child } from './operations.js';
2-
import { hydrate_nodes, hydrate_block_anchor, hydrating } from './hydration.js';
1+
import { hydrate_nodes, hydrating } from './hydration.js';
32
import { is_array } from '../utils.js';
43

54
/** @param {string} html */
@@ -74,7 +73,6 @@ export function remove(current) {
7473
* @returns {Element | Comment | (Element | Comment | Text)[]}
7574
*/
7675
export function reconcile_html(target, value, svg) {
77-
hydrate_block_anchor(target);
7876
if (hydrating) {
7977
return hydrate_nodes;
8078
}

0 commit comments

Comments
 (0)