pull/12215/head
Rich Harris 2 months ago
parent 23484d6875
commit 239ccd5666

@ -32,6 +32,21 @@ export function push_template_node(
return dom;
}
/**
*
* @param {import('#client').TemplateNode | null} start
* @param {import('#client').TemplateNode} end
*/
function assign_nodes(start, end) {
const effect = /** @type {import('#client').Effect} */ (current_effect);
if (effect.nodes === null) {
effect.nodes = { start, end };
} else {
effect.nodes.end = end;
}
}
/**
* @param {string} content
* @param {number} flags
@ -45,8 +60,12 @@ export function template(content, flags) {
/** @type {Node} */
var node;
var has_start = !content.startsWith('<!>');
return () => {
if (hydrating) {
assign_nodes(has_start ? hydrate_nodes[0] : null, hydrate_nodes[hydrate_nodes.length - 1]);
push_template_node(is_fragment ? hydrate_nodes : hydrate_start);
return hydrate_start;
}
@ -58,6 +77,16 @@ export function template(content, flags) {
var clone = use_import_node ? document.importNode(node, true) : node.cloneNode(true);
var start = is_fragment
? has_start
? /** @type {import('#client').TemplateNode} */ (clone.firstChild)
: null
: /** @type {import('#client').TemplateNode} */ (clone);
var end = /** @type {import('#client').TemplateNode} */ (is_fragment ? clone.lastChild : clone);
assign_nodes(start, end);
push_template_node(
is_fragment
? /** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes])
@ -101,32 +130,47 @@ export function template_with_script(content, flags) {
/*#__NO_SIDE_EFFECTS__*/
export function ns_template(content, flags, ns = 'svg') {
var is_fragment = (flags & TEMPLATE_FRAGMENT) !== 0;
var fn = template(`<${ns}>${content}</${ns}>`, 0); // we don't need to worry about using importNode for namespaced elements
var wrapped = `<${ns}>${content}</${ns}>`;
/** @type {Element | DocumentFragment} */
var node;
var has_start = !content.startsWith('<!>');
return () => {
if (hydrating) {
assign_nodes(has_start ? hydrate_nodes[0] : null, hydrate_nodes[hydrate_nodes.length - 1]);
push_template_node(is_fragment ? hydrate_nodes : hydrate_start);
return hydrate_start;
}
if (!node) {
var wrapper = /** @type {Element} */ (fn());
var fragment = /** @type {Element} */ (create_fragment_from_html(wrapped));
var root = fragment.firstChild;
if ((flags & TEMPLATE_FRAGMENT) === 0) {
node = /** @type {Element} */ (wrapper.firstChild);
} else {
if (is_fragment) {
node = document.createDocumentFragment();
while (wrapper.firstChild) {
node.appendChild(wrapper.firstChild);
while (root.firstChild) {
node.appendChild(root.firstChild);
}
} else {
node = /** @type {Element} */ (root.firstChild);
}
}
var clone = node.cloneNode(true);
var start = is_fragment
? has_start
? /** @type {import('#client').TemplateNode} */ (clone.firstChild)
: null
: /** @type {import('#client').TemplateNode} */ (clone);
var end = /** @type {import('#client').TemplateNode} */ (is_fragment ? clone.lastChild : clone);
assign_nodes(start, end);
push_template_node(
is_fragment
? /** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes])
@ -208,7 +252,11 @@ function run_scripts(node) {
*/
/*#__NO_SIDE_EFFECTS__*/
export function text(anchor) {
if (!hydrating) return push_template_node(empty());
if (!hydrating) {
var t = empty();
assign_nodes(t, t);
return push_template_node(t);
}
var node = hydrate_start;
@ -218,6 +266,7 @@ export function text(anchor) {
anchor.before((node = empty()));
}
assign_nodes(node, node);
push_template_node(node);
return node;
}

@ -85,6 +85,7 @@ function create_effect(type, fn, sync) {
ctx: current_component_context,
deps: null,
dom: null,
nodes: null,
f: type | DIRTY,
first: null,
fn,
@ -337,11 +338,21 @@ export function execute_effect_teardown(effect) {
export function destroy_effect(effect, remove_dom = true) {
var dom = effect.dom;
var removed = false;
if (remove_dom) {
var start = get_first_node(effect);
var end = get_last_node(effect);
remove_nodes(start, end);
removed = true;
}
if (dom !== null && remove_dom) {
remove(dom);
// remove(dom);
}
destroy_effect_children(effect, remove_dom);
destroy_effect_children(effect, remove_dom && !removed);
remove_reactions(effect, 0);
set_signal_status(effect, DESTROYED);
@ -372,6 +383,56 @@ export function destroy_effect(effect, remove_dom = true) {
null;
}
/**
* @param {import('#client').Effect} effect
*/
function get_first_node(effect) {
if (effect.nodes !== null) {
if (effect.nodes.start !== null) {
return effect.nodes.start;
}
}
if (effect.first !== null) {
return get_first_node(effect.first);
}
return null;
}
/**
* @param {import('#client').Effect} effect
*/
function get_last_node(effect) {
if (effect.nodes !== null) {
return effect.nodes.end;
}
if (effect.last !== null) {
return get_last_node(effect.last);
}
return null;
}
/**
* @param {import('#client').TemplateNode} start
* @param {import('#client').TemplateNode} end
*/
function remove_nodes(start, end) {
/** @type {import('#client').TemplateNode | null} */
var node = start;
while (node !== null) {
/** @type {import('#client').TemplateNode | null} */
var next =
node === end ? null : /** @type {import('#client').TemplateNode} */ (node.nextSibling);
node.remove();
node = next;
}
}
/**
* Detach an effect from the effect tree, freeing up memory and
* reducing the amount of work that happens on subsequent traversals

@ -1,4 +1,4 @@
import type { ComponentContext, Dom, Equals, TransitionManager } from '#client';
import type { ComponentContext, Dom, Equals, TemplateNode, TransitionManager } from '#client';
export interface Signal {
/** Flags bitmask */
@ -37,6 +37,7 @@ export interface Derived<V = unknown> extends Value<V>, Reaction {
export interface Effect extends Reaction {
parent: Effect | null;
dom: Dom | null;
nodes: null | { start: null | TemplateNode; end: TemplateNode };
/** The associated component context */
ctx: null | ComponentContext;
/** The effect function */

@ -555,7 +555,7 @@ function flush_queued_effects(effects) {
// don't know if we need to keep them until they are executed. Doing the check
// here (rather than in `execute_effect`) allows us to skip the work for
// immediate effects.
if (effect.deps === null && effect.first === null && effect.dom === null) {
if (effect.deps === null && effect.first === null && effect.nodes === null) {
if (effect.teardown === null) {
// remove this effect from the graph
unlink_effect(effect);

Loading…
Cancel
Save