Skip to content

Commit 32b1824

Browse files
authored
chore: more hydration stuff (#10896)
* this condition is always true * rename child_frag to first_child * no need to use is_array, it is always an array when hydrating * simplify close_template * spread is faster than Array.from * avoid reassigning argument
1 parent 9b7331c commit 32b1824

File tree

11 files changed

+38
-36
lines changed

11 files changed

+38
-36
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ function create_block(parent, name, nodes, context) {
12021202
} else {
12031203
/** @type {(is_text: boolean) => import('estree').Expression} */
12041204
const expression = (is_text) =>
1205-
is_text ? b.call('$.child_frag', id, b.true) : b.call('$.child_frag', id);
1205+
is_text ? b.call('$.first_child', id, b.true) : b.call('$.first_child', id);
12061206

12071207
process_children(trimmed, expression, false, { ...context, state });
12081208

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,18 +134,19 @@ export function child(node) {
134134
}
135135

136136
/**
137-
* @template {Node | Node[]} N
138-
* @param {N} node
137+
* @param {DocumentFragment | import('#client').TemplateNode[]} fragment
139138
* @param {boolean} is_text
140139
* @returns {Node | null}
141140
*/
142141
/*#__NO_SIDE_EFFECTS__*/
143-
export function child_frag(node, is_text) {
142+
export function first_child(fragment, is_text) {
144143
if (!hydrating) {
145-
return first_child_get.call(/** @type {Node} */ (node));
144+
// when not hydrating, `fragment` is a `DocumentFragment` (the result of calling `open_frag`)
145+
return first_child_get.call(/** @type {DocumentFragment} */ (fragment));
146146
}
147147

148-
const first_node = /** @type {import('#client').TemplateNode[]} */ (node)[0];
148+
// when we _are_ hydrating, `fragment` is an array of nodes
149+
const first_node = /** @type {import('#client').TemplateNode[]} */ (fragment)[0];
149150

150151
// if an {expression} is empty during SSR, there might be no
151152
// text node to hydrate — we must therefore create one

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export function reconcile_html(target, value, svg) {
9393
content = /** @type {DocumentFragment} */ (/** @type {unknown} */ (content.firstChild));
9494
}
9595
var clone = content.cloneNode(true);
96-
frag_nodes = Array.from(clone.childNodes);
96+
frag_nodes = [...clone.childNodes];
9797
frag_nodes.forEach((node) => {
9898
target.before(node);
9999
});

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

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,17 @@ export function svg_template_with_script(svg, return_fragment) {
8787
* @param {() => Node} [template_element_fn]
8888
* @returns {Element | DocumentFragment | Node[]}
8989
*/
90+
/*#__NO_SIDE_EFFECTS__*/
9091
function open_template(is_fragment, use_clone_node, anchor, template_element_fn) {
9192
if (hydrating) {
9293
if (anchor !== null) {
94+
// TODO why is this sometimes null and sometimes not? needs clear documentation
9395
hydrate_block_anchor(anchor);
9496
}
95-
// In ssr+hydration optimization mode, we might remove the template_element,
96-
// so we need to is_fragment flag to properly handle hydrated content accordingly.
97-
const nodes = hydrate_nodes;
98-
if (nodes !== null) {
99-
return is_fragment ? nodes : /** @type {Element} */ (nodes[0]);
100-
}
97+
98+
return is_fragment ? hydrate_nodes : /** @type {Element} */ (hydrate_nodes[0]);
10199
}
100+
102101
return use_clone_node
103102
? clone_node(/** @type {() => Element} */ (template_element_fn)(), true)
104103
: document.importNode(/** @type {() => Element} */ (template_element_fn)(), true);
@@ -108,11 +107,10 @@ function open_template(is_fragment, use_clone_node, anchor, template_element_fn)
108107
* @param {null | Text | Comment | Element} anchor
109108
* @param {() => Node} template_element_fn
110109
* @param {boolean} [use_clone_node]
111-
* @returns {Element | DocumentFragment | Node[]}
110+
* @returns {Element}
112111
*/
113-
/*#__NO_SIDE_EFFECTS__*/
114112
export function open(anchor, template_element_fn, use_clone_node = true) {
115-
return open_template(false, use_clone_node, anchor, template_element_fn);
113+
return /** @type {Element} */ (open_template(false, use_clone_node, anchor, template_element_fn));
116114
}
117115

118116
/**
@@ -121,7 +119,6 @@ export function open(anchor, template_element_fn, use_clone_node = true) {
121119
* @param {boolean} [use_clone_node]
122120
* @returns {Element | DocumentFragment | Node[]}
123121
*/
124-
/*#__NO_SIDE_EFFECTS__*/
125122
export function open_frag(anchor, template_element_fn, use_clone_node = true) {
126123
return open_template(true, use_clone_node, anchor, template_element_fn);
127124
}
@@ -175,21 +172,25 @@ export function comment(anchor) {
175172
/**
176173
* Assign the created (or in hydration mode, traversed) dom elements to the current block
177174
* and insert the elements into the dom (in client mode).
178-
* @param {Element | Text} dom
175+
* @param {import('#client').Dom} dom
179176
* @param {boolean} is_fragment
180177
* @param {null | Text | Comment | Element} anchor
181178
* @returns {import('#client').Dom}
182179
*/
183180
function close_template(dom, is_fragment, anchor) {
184-
/** @type {import('#client').Dom} */
185-
var current = is_fragment
186-
? is_array(dom)
187-
? dom
188-
: /** @type {import('#client').TemplateNode[]} */ (Array.from(dom.childNodes))
189-
: dom;
190-
191-
if (!hydrating && anchor !== null) {
192-
insert(current, anchor);
181+
var current = dom;
182+
183+
if (!hydrating) {
184+
if (is_fragment) {
185+
// if hydrating, `dom` is already an array of nodes, but if not then
186+
// we need to create an array to store it on the current effect
187+
current = /** @type {import('#client').Dom} */ ([.../** @type {Node} */ (dom).childNodes]);
188+
}
189+
190+
if (anchor !== null) {
191+
// TODO as with `open_template — why is this sometimes null and sometimes not?
192+
insert(current, anchor);
193+
}
193194
}
194195

195196
/** @type {import('#client').Effect} */ (current_effect).dom = current;

packages/svelte/src/internal/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export { proxy, unstate } from './client/proxy.js';
6464
export { create_custom_element } from './client/dom/elements/custom-element.js';
6565
export {
6666
child,
67-
child_frag,
67+
first_child,
6868
sibling,
6969
$window as window,
7070
$document as document

packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export default function Bind_this($$anchor, $$props) {
99

1010
/* Init */
1111
var fragment = $.comment($$anchor);
12-
var node = $.child_frag(fragment);
12+
var node = $.first_child(fragment);
1313

1414
$.bind_this(Foo(node, {}), ($$value) => foo = $$value, () => foo);
1515
$.close_frag($$anchor, fragment);
1616
$.pop();
17-
}
17+
}

packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default function Main($$anchor, $$props) {
1313
let y = () => 'test';
1414
/* Init */
1515
var fragment = $.open_frag($$anchor, frag, false);
16-
var div = $.child_frag(fragment);
16+
var div = $.first_child(fragment);
1717
var svg = $.sibling($.sibling(div, true));
1818
var custom_element = $.sibling($.sibling(svg, true));
1919
var div_1 = $.sibling($.sibling(custom_element, true));

packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function Each_string_template($$anchor, $$props) {
99

1010
/* Init */
1111
var fragment = $.comment($$anchor);
12-
var node = $.child_frag(fragment);
12+
var node = $.first_child(fragment);
1313

1414
$.each_indexed(
1515
node,

packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function Function_prop_no_getter($$anchor, $$props) {
1515
const plusOne = (num) => num + 1;
1616
/* Init */
1717
var fragment = $.comment($$anchor);
18-
var node = $.child_frag(fragment);
18+
var node = $.first_child(fragment);
1919

2020
Button(node, {
2121
onmousedown: () => $.set(count, $.get(count) + 1),

packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default function State_proxy_literal($$anchor, $$props) {
1919
let tpl = $.source(``);
2020
/* Init */
2121
var fragment = $.open_frag($$anchor, frag);
22-
var input = $.child_frag(fragment);
22+
var input = $.first_child(fragment);
2323

2424
$.remove_input_attr_defaults(input);
2525

packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export default function Svelte_element($$anchor, $$props) {
99
let tag = $.prop($$props, "tag", 3, 'hr');
1010
/* Init */
1111
var fragment = $.comment($$anchor);
12-
var node = $.child_frag(fragment);
12+
var node = $.first_child(fragment);
1313

1414
$.element(node, tag, false);
1515
$.close_frag($$anchor, fragment);
1616
$.pop();
17-
}
17+
}

0 commit comments

Comments
 (0)