Skip to content

Commit 80f62b5

Browse files
authored
chore: use template_effect for html tags (#15779)
1 parent 19836e2 commit 80f62b5

File tree

2 files changed

+69
-72
lines changed

2 files changed

+69
-72
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @import { Effect, TemplateNode } from '#client' */
22
import { FILENAME, HYDRATION_ERROR } from '../../../../constants.js';
3-
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
3+
import { remove_effect_dom, template_effect } from '../../reactivity/effects.js';
44
import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from '../hydration.js';
55
import { create_fragment_from_html } from '../reconciler.js';
66
import { assign_nodes } from '../template.js';
@@ -9,6 +9,7 @@ import { hash, sanitize_location } from '../../../../utils.js';
99
import { DEV } from 'esm-env';
1010
import { dev_current_component_function } from '../../context.js';
1111
import { get_first_child, get_next_sibling } from '../operations.js';
12+
import { active_effect } from '../../runtime.js';
1213

1314
/**
1415
* @param {Element} element
@@ -44,79 +45,71 @@ export function html(node, get_value, svg = false, mathml = false, skip_warning
4445

4546
var value = '';
4647

47-
/** @type {Effect | undefined} */
48-
var effect;
48+
template_effect(() => {
49+
var effect = /** @type {Effect} */ (active_effect);
4950

50-
block(() => {
5151
if (value === (value = get_value() ?? '')) {
52-
if (hydrating) {
53-
hydrate_next();
54-
}
52+
if (hydrating) hydrate_next();
5553
return;
5654
}
5755

58-
if (effect !== undefined) {
59-
destroy_effect(effect);
60-
effect = undefined;
56+
if (effect.nodes_start !== null) {
57+
remove_effect_dom(effect.nodes_start, /** @type {TemplateNode} */ (effect.nodes_end));
58+
effect.nodes_start = effect.nodes_end = null;
6159
}
6260

6361
if (value === '') return;
6462

65-
effect = branch(() => {
66-
if (hydrating) {
67-
// We're deliberately not trying to repair mismatches between server and client,
68-
// as it's costly and error-prone (and it's an edge case to have a mismatch anyway)
69-
var hash = /** @type {Comment} */ (hydrate_node).data;
70-
var next = hydrate_next();
71-
var last = next;
72-
73-
while (
74-
next !== null &&
75-
(next.nodeType !== 8 || /** @type {Comment} */ (next).data !== '')
76-
) {
77-
last = next;
78-
next = /** @type {TemplateNode} */ (get_next_sibling(next));
79-
}
80-
81-
if (next === null) {
82-
w.hydration_mismatch();
83-
throw HYDRATION_ERROR;
84-
}
85-
86-
if (DEV && !skip_warning) {
87-
check_hash(/** @type {Element} */ (next.parentNode), hash, value);
88-
}
89-
90-
assign_nodes(hydrate_node, last);
91-
anchor = set_hydrate_node(next);
92-
return;
93-
}
63+
if (hydrating) {
64+
// We're deliberately not trying to repair mismatches between server and client,
65+
// as it's costly and error-prone (and it's an edge case to have a mismatch anyway)
66+
var hash = /** @type {Comment} */ (hydrate_node).data;
67+
var next = hydrate_next();
68+
var last = next;
9469

95-
var html = value + '';
96-
if (svg) html = `<svg>${html}</svg>`;
97-
else if (mathml) html = `<math>${html}</math>`;
70+
while (next !== null && (next.nodeType !== 8 || /** @type {Comment} */ (next).data !== '')) {
71+
last = next;
72+
next = /** @type {TemplateNode} */ (get_next_sibling(next));
73+
}
9874

99-
// Don't use create_fragment_with_script_from_html here because that would mean script tags are executed.
100-
// @html is basically `.innerHTML = ...` and that doesn't execute scripts either due to security reasons.
101-
/** @type {DocumentFragment | Element} */
102-
var node = create_fragment_from_html(html);
75+
if (next === null) {
76+
w.hydration_mismatch();
77+
throw HYDRATION_ERROR;
78+
}
10379

104-
if (svg || mathml) {
105-
node = /** @type {Element} */ (get_first_child(node));
80+
if (DEV && !skip_warning) {
81+
check_hash(/** @type {Element} */ (next.parentNode), hash, value);
10682
}
10783

108-
assign_nodes(
109-
/** @type {TemplateNode} */ (get_first_child(node)),
110-
/** @type {TemplateNode} */ (node.lastChild)
111-
);
112-
113-
if (svg || mathml) {
114-
while (get_first_child(node)) {
115-
anchor.before(/** @type {Node} */ (get_first_child(node)));
116-
}
117-
} else {
118-
anchor.before(node);
84+
assign_nodes(hydrate_node, last);
85+
anchor = set_hydrate_node(next);
86+
return;
87+
}
88+
89+
var html = value + '';
90+
if (svg) html = `<svg>${html}</svg>`;
91+
else if (mathml) html = `<math>${html}</math>`;
92+
93+
// Don't use create_fragment_with_script_from_html here because that would mean script tags are executed.
94+
// @html is basically `.innerHTML = ...` and that doesn't execute scripts either due to security reasons.
95+
/** @type {DocumentFragment | Element} */
96+
var node = create_fragment_from_html(html);
97+
98+
if (svg || mathml) {
99+
node = /** @type {Element} */ (get_first_child(node));
100+
}
101+
102+
assign_nodes(
103+
/** @type {TemplateNode} */ (get_first_child(node)),
104+
/** @type {TemplateNode} */ (node.lastChild)
105+
);
106+
107+
if (svg || mathml) {
108+
while (get_first_child(node)) {
109+
anchor.before(/** @type {Node} */ (get_first_child(node)));
119110
}
120-
});
111+
} else {
112+
anchor.before(node);
113+
}
121114
});
122115
}

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

+16-12
Original file line numberDiff line numberDiff line change
@@ -427,18 +427,7 @@ export function destroy_effect(effect, remove_dom = true) {
427427
var removed = false;
428428

429429
if ((remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes_start !== null) {
430-
/** @type {TemplateNode | null} */
431-
var node = effect.nodes_start;
432-
var end = effect.nodes_end;
433-
434-
while (node !== null) {
435-
/** @type {TemplateNode | null} */
436-
var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node));
437-
438-
node.remove();
439-
node = next;
440-
}
441-
430+
remove_effect_dom(effect.nodes_start, /** @type {TemplateNode} */ (effect.nodes_end));
442431
removed = true;
443432
}
444433

@@ -480,6 +469,21 @@ export function destroy_effect(effect, remove_dom = true) {
480469
null;
481470
}
482471

472+
/**
473+
*
474+
* @param {TemplateNode | null} node
475+
* @param {TemplateNode} end
476+
*/
477+
export function remove_effect_dom(node, end) {
478+
while (node !== null) {
479+
/** @type {TemplateNode | null} */
480+
var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node));
481+
482+
node.remove();
483+
node = next;
484+
}
485+
}
486+
483487
/**
484488
* Detach an effect from the effect tree, freeing up memory and
485489
* reducing the amount of work that happens on subsequent traversals

0 commit comments

Comments
 (0)