diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index 5dcf52d914..b437c17389 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -9,8 +9,7 @@ import { set_current_reaction } from '../../runtime.js'; import { destroy_effect, pause_effect, render_effect } from '../../reactivity/effects.js'; -import { DESTROYED, INERT } from '../../constants.js'; -import { create_block } from './utils.js'; +import { INERT } from '../../constants.js'; /** * @template V @@ -22,8 +21,6 @@ import { create_block } from './utils.js'; * @returns {void} */ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { - const block = create_block(); - const component_context = current_component_context; hydrate_block_anchor(anchor); @@ -48,7 +45,7 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { set_current_effect(branch); set_current_reaction(branch); // TODO do we need both? set_current_component_context(component_context); - var effect = render_effect(() => fn(anchor, value), {}, true); + var effect = render_effect(() => fn(anchor, value), true); set_current_component_context(null); set_current_reaction(null); set_current_effect(null); @@ -60,18 +57,6 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { return effect; } - /** @param {import('#client').Effect} effect */ - function pause(effect) { - if ((effect.f & DESTROYED) !== 0) return; - const block = effect.block; - - pause_effect(effect, () => { - // TODO make this unnecessary - const dom = block?.d; - if (dom) remove(dom); - }); - } - const branch = render_effect(() => { if (input === (input = get_input())) return; @@ -80,20 +65,20 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { if (pending_fn) { if (pending_effect && (pending_effect.f & INERT) === 0) { - if (pending_effect.block?.d) remove(pending_effect.block.d); + if (pending_effect.dom) remove(pending_effect.dom); destroy_effect(pending_effect); } - pending_effect = render_effect(() => pending_fn(anchor), {}, true); + pending_effect = render_effect(() => pending_fn(anchor), true); } - if (then_effect) pause(then_effect); - if (catch_effect) pause(catch_effect); + if (then_effect) pause_effect(then_effect); + if (catch_effect) pause_effect(catch_effect); promise.then( (value) => { if (promise !== input) return; - if (pending_effect) pause(pending_effect); + if (pending_effect) pause_effect(pending_effect); if (then_fn) { then_effect = create_effect(then_fn, value); @@ -101,7 +86,7 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { }, (error) => { if (promise !== input) return; - if (pending_effect) pause(pending_effect); + if (pending_effect) pause_effect(pending_effect); if (catch_fn) { catch_effect = create_effect(catch_fn, error); @@ -109,24 +94,24 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { } ); } else { - if (pending_effect) pause(pending_effect); - if (catch_effect) pause(catch_effect); + if (pending_effect) pause_effect(pending_effect); + if (catch_effect) pause_effect(catch_effect); if (then_fn) { if (then_effect) { - if (then_effect.block?.d) remove(then_effect.block.d); + if (then_effect.dom) remove(then_effect.dom); destroy_effect(then_effect); } - then_effect = render_effect(() => then_fn(anchor, input), {}, true); + then_effect = render_effect(() => then_fn(anchor, input), true); } } - }, block); + }); branch.ondestroy = () => { // TODO this sucks, tidy it up - if (pending_effect?.block?.d) remove(pending_effect.block.d); - if (then_effect?.block?.d) remove(then_effect.block.d); - if (catch_effect?.block?.d) remove(catch_effect.block.d); + if (pending_effect?.dom) remove(pending_effect.dom); + if (then_effect?.dom) remove(then_effect.dom); + if (catch_effect?.dom) remove(catch_effect.dom); }; } diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index bc0f035378..ce17cced94 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -19,6 +19,7 @@ import { untrack } from '../../runtime.js'; import { destroy_effect, pause_effect, + pause_effects, render_effect, resume_effect, user_effect @@ -26,21 +27,20 @@ import { import { source, mutable_source, set } from '../../reactivity/sources.js'; import { is_array, is_frozen, map_get, map_set } from '../../utils.js'; import { STATE_SYMBOL } from '../../constants.js'; -import { create_block } from './utils.js'; -var NEW_BLOCK = -1; -var LIS_BLOCK = -2; +var NEW_ITEM = -1; +var LIS_ITEM = -2; /** * The row of a keyed each block that is currently updating. We track this * so that `animate:` directives have something to attach themselves to * @type {import('#client').EachItem | null} */ -export let current_each_item_block = null; +export let current_each_item = null; -/** @param {import('#client').EachItem | null} block */ -export function set_current_each_item_block(block) { - current_each_item_block = block; +/** @param {import('#client').EachItem | null} item */ +export function set_current_each_item(item) { + current_each_item = item; } /** @@ -55,8 +55,6 @@ export function set_current_each_item_block(block) { * @returns {void} */ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, reconcile_fn) { - var block = create_block(); - /** @type {import('#client').EachState} */ var state = { flags, items: [] }; @@ -71,132 +69,122 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re /** @type {import('#client').Effect | null} */ var fallback = null; - var effect = render_effect( - () => { - var collection = get_collection(); + var effect = render_effect(() => { + var collection = get_collection(); - var array = is_array(collection) - ? collection - : collection == null - ? [] - : Array.from(collection); + var array = is_array(collection) + ? collection + : collection == null + ? [] + : Array.from(collection); - var keys = get_key === null ? array : array.map(get_key); + var keys = get_key === null ? array : array.map(get_key); - var length = array.length; + var length = array.length; - // If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items - // are treated as reactive, so they get wrapped in a signal. - var flags = state.flags; - if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) { - flags ^= EACH_IS_STRICT_EQUALS; + // If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items + // are treated as reactive, so they get wrapped in a signal. + var flags = state.flags; + if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) { + flags ^= EACH_IS_STRICT_EQUALS; - // Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals. - if ((flags & EACH_KEYED) !== 0 && (flags & EACH_ITEM_REACTIVE) === 0) { - flags ^= EACH_ITEM_REACTIVE; - } + // Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals. + if ((flags & EACH_KEYED) !== 0 && (flags & EACH_ITEM_REACTIVE) === 0) { + flags ^= EACH_ITEM_REACTIVE; } + } - /** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ - let mismatch = false; - - if (hydrating) { - var is_else = - /** @type {Comment} */ (current_hydration_fragment?.[0])?.data === 'ssr:each_else'; + /** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ + let mismatch = false; + + if (hydrating) { + var is_else = + /** @type {Comment} */ (current_hydration_fragment?.[0])?.data === 'ssr:each_else'; + + if (is_else !== (length === 0)) { + // hydration mismatch — remove the server-rendered DOM and start over + remove(current_hydration_fragment); + set_current_hydration_fragment(null); + mismatch = true; + } else if (is_else) { + // Remove the each_else comment node or else it will confuse the subsequent hydration algorithm + /** @type {import('#client').TemplateNode[]} */ (current_hydration_fragment).shift(); + } + } - if (is_else !== (length === 0)) { - // hydration mismatch — remove the server-rendered DOM and start over - remove(current_hydration_fragment); - set_current_hydration_fragment(null); + // this is separate to the previous block because `hydrating` might change + if (hydrating) { + var b_items = []; + + // Hydrate block + var hydration_list = /** @type {import('#client').TemplateNode[]} */ ( + current_hydration_fragment + ); + var hydrating_node = hydration_list[0]; + + for (var i = 0; i < length; i++) { + var fragment = get_hydration_fragment(hydrating_node); + set_current_hydration_fragment(fragment); + if (!fragment) { + // If fragment is null, then that means that the server rendered less items than what + // the client code specifies -> break out and continue with client-side node creation mismatch = true; - } else if (is_else) { - // Remove the each_else comment node or else it will confuse the subsequent hydration algorithm - /** @type {import('#client').TemplateNode[]} */ (current_hydration_fragment).shift(); + break; } - } - // this is separate to the previous block because `hydrating` might change - if (hydrating) { - var b_blocks = []; + b_items[i] = create_item(array[i], keys?.[i], i, render_fn, flags); - // Hydrate block - var hydration_list = /** @type {import('#client').TemplateNode[]} */ ( - current_hydration_fragment + // TODO helperise this + hydrating_node = /** @type {import('#client').TemplateNode} */ ( + /** @type {Node} */ ( + /** @type {Node} */ (fragment[fragment.length - 1] || hydrating_node).nextSibling + ).nextSibling ); - var hydrating_node = hydration_list[0]; - - for (var i = 0; i < length; i++) { - var fragment = get_hydration_fragment(hydrating_node); - set_current_hydration_fragment(fragment); - if (!fragment) { - // If fragment is null, then that means that the server rendered less items than what - // the client code specifies -> break out and continue with client-side node creation - mismatch = true; - break; - } - - b_blocks[i] = create_item(array[i], keys?.[i], i, render_fn, flags); - - // TODO helperise this - hydrating_node = /** @type {import('#client').TemplateNode} */ ( - /** @type {Node} */ ( - /** @type {Node} */ (fragment[fragment.length - 1] || hydrating_node).nextSibling - ).nextSibling - ); - } + } - remove_excess_hydration_nodes(hydration_list, hydrating_node); + remove_excess_hydration_nodes(hydration_list, hydrating_node); - state.items = b_blocks; - } + state.items = b_items; + } - if (!hydrating) { - // TODO add 'empty controlled block' optimisation here - reconcile_fn(array, state, anchor, render_fn, flags, keys); - } + if (!hydrating) { + // TODO add 'empty controlled block' optimisation here + reconcile_fn(array, state, anchor, render_fn, flags, keys); + } - if (fallback_fn !== null) { - if (length === 0) { - if (fallback) { - resume_effect(fallback); - } else { - fallback = render_effect( - () => { - fallback_fn(anchor); - var dom = block.d; // TODO would be nice if this was just returned from the managed effect function... - - return () => { - if (dom !== null) { - remove(dom); - dom = null; - } - }; - }, - block, - true - ); - } - } else if (fallback !== null) { - pause_effect(fallback, () => { - fallback = null; - }); + if (fallback_fn !== null) { + if (length === 0) { + if (fallback) { + resume_effect(fallback); + } else { + fallback = render_effect(() => { + var dom = fallback_fn(anchor); + + return () => { + if (dom !== undefined) { + remove(dom); + } + }; + }, true); } + } else if (fallback !== null) { + pause_effect(fallback, () => { + fallback = null; + }); } + } - if (mismatch) { - // Set a fragment so that Svelte continues to operate in hydration mode - set_current_hydration_fragment([]); - } - }, - block, - false - ); + if (mismatch) { + // Set a fragment so that Svelte continues to operate in hydration mode + set_current_hydration_fragment([]); + } + }); effect.ondestroy = () => { for (var item of state.items) { - if (item.d !== null) { + if (item.e.dom !== null) { + remove(item.e.dom); destroy_effect(item.e); - remove(item.d); } } @@ -274,26 +262,14 @@ function reconcile_indexed_array(array, state, anchor, render_fn, flags) { state.items = b_items; } else if (a > b) { // remove items - var remaining = a - b; - - var clear = () => { - for (var i = b; i < a; i += 1) { - var block = a_items[i]; - if (block.d) remove(block.d); - } + var effects = []; + for (i = b; i < a; i += 1) { + effects.push(a_items[i].e); + } + pause_effects(effects, () => { state.items.length = b; - }; - - var check = () => { - if (--remaining === 0) { - clear(); - } - }; - - for (; i < a; i += 1) { - pause_effect(a_items[i].e, check); - } + }); } } @@ -311,42 +287,42 @@ function reconcile_indexed_array(array, state, anchor, render_fn, flags) { * @returns {void} */ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { - var a_blocks = state.items; + var a_items = state.items; - var a = a_blocks.length; + var a = a_items.length; var b = array.length; /** @type {Array} */ - var b_blocks = Array(b); + var b_items = Array(b); var is_animated = (flags & EACH_IS_ANIMATED) !== 0; var should_update = (flags & (EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE)) !== 0; var start = 0; - var block; + var item; - /** @type {Array} */ + /** @type {import('#client').Effect[]} */ var to_destroy = []; // Step 1 — trim common suffix - while (a > 0 && b > 0 && a_blocks[a - 1].k === keys[b - 1]) { - block = b_blocks[--b] = a_blocks[--a]; - anchor = get_first_child(block); + while (a > 0 && b > 0 && a_items[a - 1].k === keys[b - 1]) { + item = b_items[--b] = a_items[--a]; + anchor = get_first_child(item); - resume_effect(block.e); + resume_effect(item.e); if (should_update) { - update_item(block, array[b], b, flags); + update_item(item, array[b], b, flags); } } // Step 2 — trim common prefix - while (start < a && start < b && a_blocks[start].k === keys[start]) { - block = b_blocks[start] = a_blocks[start]; + while (start < a && start < b && a_items[start].k === keys[start]) { + item = b_items[start] = a_items[start]; - resume_effect(block.e); + resume_effect(item.e); if (should_update) { - update_item(block, array[start], start, flags); + update_item(item, array[start], start, flags); } start += 1; @@ -356,14 +332,14 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { if (start === a) { // add only while (start < b) { - block = create_item(array[start], keys[start], start, render_fn, flags); - b_blocks[start++] = block; - insert_item(block, anchor); + item = create_item(array[start], keys[start], start, render_fn, flags); + b_items[start++] = item; + insert_item(item, anchor); } } else if (start === b) { // remove only while (start < a) { - to_destroy.push(a_blocks[start++]); + to_destroy.push(a_items[start++].e); } } else { // reconcile @@ -372,78 +348,78 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { var indexes = new Map(); var i; var index; - var last_block; + var last_item; var last_sibling; - // store the indexes of each block in the new world + // store the indexes of each item in the new world for (i = start; i < b; i += 1) { - sources[i - start] = NEW_BLOCK; + sources[i - start] = NEW_ITEM; map_set(indexes, keys[i], i); } /** @type {Array} */ var to_animate = []; if (is_animated) { - // for all blocks that were in both the old and the new list, + // for all items that were in both the old and the new list, // measure them and store them in `to_animate` so we can // apply animations once the DOM has been updated - for (i = 0; i < a_blocks.length; i += 1) { - block = a_blocks[i]; - if (indexes.has(block.k)) { - block.a?.measure(); - to_animate.push(block); + for (i = 0; i < a_items.length; i += 1) { + item = a_items[i]; + if (indexes.has(item.k)) { + item.a?.measure(); + to_animate.push(item); } } } - // populate the `sources` array for each old block with + // populate the `sources` array for each old item with // its new index, so that we can calculate moves for (i = start; i < a; i += 1) { - block = a_blocks[i]; - index = map_get(indexes, block.k); + item = a_items[i]; + index = map_get(indexes, item.k); - resume_effect(block.e); + resume_effect(item.e); if (index === undefined) { - to_destroy.push(block); + to_destroy.push(item.e); } else { moved = true; sources[index - start] = i; - b_blocks[index] = block; + b_items[index] = item; if (is_animated) { - to_animate.push(block); + to_animate.push(item); } } } - // if we need to move blocks (as opposed to just adding/removing), + // if we need to move items (as opposed to just adding/removing), // figure out how to do so efficiently (I would be lying if I said // I fully understand this part) if (moved) { mark_lis(sources); } - // working from the back, insert new or moved blocks + // working from the back, insert new or moved items while (b-- > start) { index = sources[b - start]; - var insert = index === NEW_BLOCK; + var insert = index === NEW_ITEM; if (insert) { - block = create_item(array[b], keys[b], b, render_fn, flags); + item = create_item(array[b], keys[b], b, render_fn, flags); } else { - block = b_blocks[b]; + item = b_items[b]; if (should_update) { - update_item(block, array[b], b, flags); + update_item(item, array[b], b, flags); } } - if (insert || (moved && index !== LIS_BLOCK)) { - last_sibling = last_block === undefined ? anchor : get_first_child(last_block); - anchor = insert_item(block, last_sibling); + if (insert || (moved && index !== LIS_ITEM)) { + last_sibling = last_item === undefined ? anchor : get_first_child(last_item); + anchor = insert_item(item, last_sibling); } - last_block = b_blocks[b] = block; + last_item = b_items[b] = item; } if (to_animate.length > 0) { @@ -453,36 +429,17 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { // - https://svelte.dev/repl/6e891305e9644a7ca7065fa95c79d2d2?version=4.2.9 user_effect(() => { untrack(() => { - for (block of to_animate) { - block.a?.apply(); + for (item of to_animate) { + item.a?.apply(); } }); }); } } - var remaining = to_destroy.length; - if (remaining > 0) { - var clear = () => { - for (block of to_destroy) { - if (block.d) remove(block.d); - } - - state.items = b_blocks; - }; - - var check = () => { - if (--remaining === 0) { - clear(); - } - }; - - for (block of to_destroy) { - pause_effect(block.e, check); - } - } else { - state.items = b_blocks; - } + pause_effects(to_destroy, () => { + state.items = b_items; + }); } /** @@ -524,7 +481,7 @@ function mark_lis(a) { var hi; // Skip -1 values at the start of the input array `a`. - for (; a[i] === NEW_BLOCK; ++i) { + for (; a[i] === NEW_ITEM; ++i) { /**/ } @@ -533,7 +490,7 @@ function mark_lis(a) { for (; i < length; ++i) { k = a[i]; - if (k !== NEW_BLOCK) { + if (k !== NEW_ITEM) { // Ignore -1 values. j = index[index_length]; @@ -567,27 +524,27 @@ function mark_lis(a) { j = index[index_length]; while (index_length-- >= 0) { - a[j] = LIS_BLOCK; + a[j] = LIS_ITEM; j = parent[j]; } } /** - * @param {import('#client').EachItem} block - * @param {Text | Element | Comment} sibling + * @param {import('#client').EachItem} item + * @param {Text | Element | Comment} anchor * @returns {Text | Element | Comment} */ -function insert_item(block, sibling) { - var current = /** @type {import('#client').TemplateNode} */ (block.d); - return insert(current, sibling); +function insert_item(item, anchor) { + var current = /** @type {import('#client').Dom} */ (item.e.dom); + return insert(current, anchor); } /** - * @param {import('#client').EachItem} block + * @param {import('#client').EachItem} item * @returns {Text | Element | Comment} */ -function get_first_child(block) { - var current = block.d; +function get_first_child(item) { + var current = item.e.dom; if (is_array(current)) { return /** @type {Text | Element | Comment} */ (current[0]); @@ -597,48 +554,40 @@ function get_first_child(block) { } /** - * @param {import('#client').EachItem} block - * @param {any} item + * @param {import('#client').EachItem} item + * @param {any} value * @param {number} index * @param {number} type * @returns {void} */ -function update_item(block, item, index, type) { +function update_item(item, value, index, type) { if ((type & EACH_ITEM_REACTIVE) !== 0) { - set(block.v, item); + set(item.v, value); } if ((type & EACH_INDEX_REACTIVE) !== 0) { - set(/** @type {import('#client').Value} */ (block.i), index); + set(/** @type {import('#client').Value} */ (item.i), index); } else { - block.i = index; + item.i = index; } } /** * @template V - * @param {V} item + * @param {V} value * @param {unknown} key * @param {number} index * @param {(anchor: null, item: V, index: number | import('#client').Value) => void} render_fn * @param {number} flags * @returns {import('#client').EachItem} */ -function create_item(item, key, index, render_fn, flags) { +function create_item(value, key, index, render_fn, flags) { var each_item_not_reactive = (flags & EACH_ITEM_REACTIVE) === 0; - var item_value = each_item_not_reactive - ? item - : (flags & EACH_IS_STRICT_EQUALS) !== 0 - ? source(item) - : mutable_source(item); - /** @type {import('#client').EachItem} */ - var block = { + var item = { a: null, // dom - d: null, - // effect // @ts-expect-error e: null, // index @@ -646,24 +595,30 @@ function create_item(item, key, index, render_fn, flags) { // key k: key, // item - v: item_value + v: each_item_not_reactive + ? value + : (flags & EACH_IS_STRICT_EQUALS) !== 0 + ? source(value) + : mutable_source(value) }; - var previous_each_item_block = current_each_item_block; + var previous_each_item = current_each_item; try { - current_each_item_block = block; + current_each_item = item; + + item.e = render_effect(() => { + var dom = render_fn(null, item.v, item.i); - block.e = render_effect( - () => { - render_fn(null, block.v, block.i); - }, - block, - true - ); + return () => { + if (dom !== undefined) { + remove(dom); + } + }; + }, true); - return block; + return item; } finally { - current_each_item_block = previous_each_item_block; + current_each_item = previous_each_item; } } diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index f257a64833..217ccac00d 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -12,7 +12,6 @@ import { render_effect, resume_effect } from '../../reactivity/effects.js'; -import { create_block } from './utils.js'; /** * @param {Comment} anchor @@ -23,16 +22,8 @@ import { create_block } from './utils.js'; * @returns {void} */ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, elseif = false) { - const block = create_block(); - hydrate_block_anchor(anchor); - /** @type {undefined | import('#client').Dom} */ - let consequent_dom; - - /** @type {undefined | import('#client').Dom} */ - let alternate_dom; - /** @type {import('#client').Effect | null} */ let consequent_effect = null; @@ -71,56 +62,24 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els if (consequent_effect) { resume_effect(consequent_effect); } else { - consequent_effect = render_effect( - () => { - consequent_dom = consequent_fn(anchor); - - return () => { - // TODO make this unnecessary by linking the dom to the effect, - // and removing automatically on teardown - if (consequent_dom !== undefined) { - remove(consequent_dom); - consequent_dom = undefined; - } - }; - }, - block, - true - ); + consequent_effect = render_effect(() => consequent_fn(anchor), true); } if (alternate_effect) { pause_effect(alternate_effect, () => { alternate_effect = null; - if (alternate_dom) remove(alternate_dom); }); } } else { if (alternate_effect) { resume_effect(alternate_effect); } else if (alternate_fn) { - alternate_effect = render_effect( - () => { - alternate_dom = alternate_fn(anchor); - - return () => { - // TODO make this unnecessary by linking the dom to the effect, - // and removing automatically on teardown - if (alternate_dom !== undefined) { - remove(alternate_dom); - alternate_dom = undefined; - } - }; - }, - block, - true - ); + alternate_effect = render_effect(() => alternate_fn(anchor), true); } if (consequent_effect) { pause_effect(consequent_effect, () => { consequent_effect = null; - if (consequent_dom) remove(consequent_dom); }); } } @@ -129,23 +88,14 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els // Set fragment so that Svelte continues to operate in hydration mode set_current_hydration_fragment([]); } - }, block); + }); if (elseif) { if_effect.f |= IS_ELSEIF; } if_effect.ondestroy = () => { - // TODO make this unnecessary by linking the dom to the effect, - // and removing automatically on teardown - if (consequent_dom !== undefined) { - remove(consequent_dom); - } - - if (alternate_dom !== undefined) { - remove(alternate_dom); - } - + // TODO why is this not automatic? this should be children of `if_effect` if (consequent_effect) { destroy_effect(consequent_effect); } diff --git a/packages/svelte/src/internal/client/dom/blocks/key.js b/packages/svelte/src/internal/client/dom/blocks/key.js index f7cb9c6dee..2c8d8980b2 100644 --- a/packages/svelte/src/internal/client/dom/blocks/key.js +++ b/packages/svelte/src/internal/client/dom/blocks/key.js @@ -3,18 +3,15 @@ import { hydrate_block_anchor } from '../hydration.js'; import { remove } from '../reconciler.js'; import { pause_effect, render_effect } from '../../reactivity/effects.js'; import { safe_not_equal } from '../../reactivity/equality.js'; -import { create_block } from './utils.js'; /** * @template V * @param {Comment} anchor * @param {() => V} get_key - * @param {(anchor: Node) => void} render_fn + * @param {(anchor: Node) => import('#client').Dom | void} render_fn * @returns {void} */ export function key_block(anchor, get_key, render_fn) { - const block = create_block(); - hydrate_block_anchor(anchor); /** @type {V | typeof UNINITIALIZED} */ @@ -30,47 +27,36 @@ export function key_block(anchor, get_key, render_fn) { */ let effects = new Set(); - const key_effect = render_effect( - () => { - if (safe_not_equal(key, (key = get_key()))) { - if (effect) { - var e = effect; - pause_effect(e, () => { - effects.delete(e); - }); - } - - effect = render_effect( - () => { - render_fn(anchor); - - const dom = block.d; - - return () => { - if (dom !== null) { - remove(dom); - } - }; - }, - block, - true, - true - ); - - // @ts-expect-error TODO tidy up - effect.d = block.d; - - effects.add(effect); + const key_effect = render_effect(() => { + if (safe_not_equal(key, (key = get_key()))) { + if (effect) { + var e = effect; + pause_effect(e, () => { + effects.delete(e); + }); } - }, - block, - false - ); + + effect = render_effect( + () => { + const dom = render_fn(anchor); + + return () => { + if (dom !== undefined) { + remove(dom); + } + }; + }, + true, + true + ); + + effects.add(effect); + } + }); key_effect.ondestroy = () => { for (const e of effects) { - // @ts-expect-error TODO tidy up. ondestroy should be totally unnecessary - if (e.d) remove(e.d); + if (e.dom) remove(e.dom); } }; } diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index ac45cb6981..62ad05c573 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -1,28 +1,31 @@ import { render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; import { untrack } from '../../runtime.js'; -import { create_block } from './utils.js'; /** - * @param {() => Function | null | undefined} get_snippet - * @param {Node} node + * @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn + * @param {() => SnippetFn | null | undefined} get_snippet + * @param {import('#client').TemplateNode} node * @param {(() => any)[]} args * @returns {void} */ export function snippet(get_snippet, node, ...args) { - const block = create_block(); + /** @type {SnippetFn | null | undefined} */ + var snippet_fn; render_effect(() => { - // Only rerender when the snippet function itself changes, - // not when an eagerly-read prop inside the snippet function changes - const snippet = get_snippet(); - if (snippet) { - untrack(() => snippet(node, ...args)); + if (snippet_fn === (snippet_fn = get_snippet())) return; + + if (snippet_fn) { + // Untrack so we only rerender when the snippet function itself changes, + // not when an eagerly-read prop inside the snippet function changes + var dom = untrack(() => /** @type {SnippetFn} */ (snippet_fn)(node, ...args)); } + return () => { - if (block.d !== null) { - remove(block.d); + if (dom !== undefined) { + remove(dom); } }; - }, block); + }); } diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js index 86fc548f04..7ef6f3d66f 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js @@ -1,7 +1,7 @@ import { hydrate_block_anchor } from '../hydration.js'; import { pause_effect, render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; -import { create_block } from './utils.js'; +import { current_effect } from '../../runtime.js'; // TODO this is very similar to `key`, can we deduplicate? @@ -10,12 +10,10 @@ import { create_block } from './utils.js'; * @template {(props: P) => void} C * @param {Comment} anchor * @param {() => C} get_component - * @param {(component: C) => void} render_fn + * @param {(component: C) => import('#client').Dom | void} render_fn * @returns {void} */ export function component(anchor, get_component, render_fn) { - const block = create_block(); - hydrate_block_anchor(anchor); /** @type {C} */ @@ -31,49 +29,36 @@ export function component(anchor, get_component, render_fn) { */ let effects = new Set(); - const component_effect = render_effect( - () => { - if (component === (component = get_component())) return; - - if (effect) { - var e = effect; - pause_effect(e, () => { - effects.delete(e); - }); - } + const component_effect = render_effect(() => { + if (component === (component = get_component())) return; - if (component) { - effect = render_effect( - () => { - render_fn(component); + if (effect) { + var e = effect; + pause_effect(e, () => { + effects.delete(e); + }); + } - const dom = block.d; + if (component) { + effect = render_effect(() => { + render_fn(component); - return () => { - if (dom !== null) { - remove(dom); - } - }; - }, - block, - true, - true - ); + // `render_fn` doesn't return anything, and we can't reference `effect` + // yet, so we reference it indirectly as `current_effect` + const dom = /** @type {import('#client').Effect} */ (current_effect).dom; - // @ts-expect-error TODO tidy up - effect.d = block.d; + return () => { + if (dom !== null) remove(dom); + }; + }, true); - effects.add(effect); - } - }, - block, - false - ); + effects.add(effect); + } + }); component_effect.ondestroy = () => { for (const e of effects) { - // @ts-expect-error TODO tidy up. ondestroy should be totally unnecessary - if (e.d) remove(e.d); + if (e.dom) remove(e.dom); } }; } diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index bfaa47e844..bd099a1985 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -10,18 +10,18 @@ import { import { remove } from '../reconciler.js'; import { is_array } from '../../utils.js'; import { set_should_intro } from '../../render.js'; -import { current_each_item_block, set_current_each_item_block } from './each.js'; -import { create_block } from './utils.js'; -import { current_block } from '../../runtime.js'; +import { current_each_item, set_current_each_item } from './each.js'; +import { current_effect } from '../../runtime.js'; /** - * @param {import('#client').Block} block + * @param {import('#client').Effect} effect * @param {Element} from * @param {Element} to * @returns {void} */ -function swap_block_dom(block, from, to) { - const dom = block.d; +function swap_block_dom(effect, from, to) { + const dom = effect.dom; + if (is_array(dom)) { for (let i = 0; i < dom.length; i++) { if (dom[i] === from) { @@ -30,7 +30,7 @@ function swap_block_dom(block, from, to) { } } } else if (dom === from) { - block.d = to; + effect.dom = to; } } @@ -42,8 +42,7 @@ function swap_block_dom(block, from, to) { * @returns {void} */ export function element(anchor, get_tag, is_svg, render_fn) { - const parent_block = /** @type {import('#client').Block} */ (current_block); - const block = create_block(); + const parent_effect = /** @type {import('#client').Effect} */ (current_effect); hydrate_block_anchor(anchor); @@ -64,15 +63,15 @@ export function element(anchor, get_tag, is_svg, render_fn) { * We track this so we can set it when changing the element, allowing any * `animate:` directive to bind itself to the correct block */ - let each_item_block = current_each_item_block; + let each_item_block = current_each_item; const wrapper = render_effect(() => { const next_tag = get_tag() || null; if (next_tag === tag) return; // See explanation of `each_item_block` above - var previous_each_item_block = current_each_item_block; - set_current_each_item_block(each_item_block); + var previous_each_item = current_each_item; + set_current_each_item(each_item_block); // We try our best infering the namespace in case it's not possible to determine statically, // but on the first render on the client (without hydration) the parent will be undefined, @@ -103,51 +102,46 @@ export function element(anchor, get_tag, is_svg, render_fn) { } if (next_tag && next_tag !== current_tag) { - effect = render_effect( - () => { - const prev_element = element; - element = hydrating - ? /** @type {Element} */ (current_hydration_fragment[0]) - : ns - ? document.createElementNS(ns, next_tag) - : document.createElement(next_tag); - - if (render_fn) { - let anchor; - if (hydrating) { - // Use the existing ssr comment as the anchor so that the inner open and close - // methods can pick up the existing nodes correctly - anchor = /** @type {Comment} */ (element.firstChild); - } else { - anchor = empty(); - element.appendChild(anchor); - } - render_fn(element, anchor); + effect = render_effect(() => { + const prev_element = element; + element = hydrating + ? /** @type {Element} */ (current_hydration_fragment[0]) + : ns + ? document.createElementNS(ns, next_tag) + : document.createElement(next_tag); + + if (render_fn) { + let anchor; + if (hydrating) { + // Use the existing ssr comment as the anchor so that the inner open and close + // methods can pick up the existing nodes correctly + anchor = /** @type {Comment} */ (element.firstChild); + } else { + anchor = empty(); + element.appendChild(anchor); } + render_fn(element, anchor); + } - anchor.before(element); + anchor.before(element); - if (prev_element) { - swap_block_dom(parent_block, prev_element, element); - prev_element.remove(); - } - }, - block, - true - ); + if (prev_element) { + swap_block_dom(parent_effect, prev_element, element); + prev_element.remove(); + } + }, true); } tag = next_tag; if (tag) current_tag = tag; set_should_intro(true); - set_current_each_item_block(previous_each_item_block); - }, block); + set_current_each_item(previous_each_item); + }); wrapper.ondestroy = () => { if (element !== null) { remove(element); - block.d = null; element = null; } diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js index bf70cd3e98..3c6bfbcf68 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js @@ -7,15 +7,12 @@ import { import { empty } from '../operations.js'; import { render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; -import { create_block } from './utils.js'; /** - * @param {(anchor: Node | null) => void} render_fn + * @param {(anchor: Node | null) => import('#client').Dom | void} render_fn * @returns {void} */ export function head(render_fn) { - const block = create_block(); - // The head function may be called after the first hydration pass and ssr comment nodes may still be present, // therefore we need to skip that when we detect that we're not in hydration mode. let hydration_fragment = null; @@ -29,28 +26,27 @@ export function head(render_fn) { } try { - const head_effect = render_effect( - () => { - const current = block.d; - if (current !== null) { - remove(current); - block.d = null; - } - let anchor = null; - if (!hydrating) { - anchor = empty(); - document.head.appendChild(anchor); - } - render_fn(anchor); - }, - block, - false - ); + /** @type {import('#client').Dom | null} */ + var dom = null; + + const head_effect = render_effect(() => { + if (dom !== null) { + remove(dom); + head_effect.dom = dom = null; + } + + let anchor = null; + if (!hydrating) { + anchor = empty(); + document.head.appendChild(anchor); + } + + dom = render_fn(anchor) ?? null; + }); head_effect.ondestroy = () => { - const current = block.d; - if (current !== null) { - remove(current); + if (dom !== null) { + remove(dom); } }; } finally { diff --git a/packages/svelte/src/internal/client/dom/blocks/utils.js b/packages/svelte/src/internal/client/dom/blocks/utils.js deleted file mode 100644 index f1214ab68c..0000000000 --- a/packages/svelte/src/internal/client/dom/blocks/utils.js +++ /dev/null @@ -1,7 +0,0 @@ -/** @returns {import('#client').Block} */ -export function create_block() { - return { - // dom - d: null - }; -} diff --git a/packages/svelte/src/internal/client/dom/elements/misc.js b/packages/svelte/src/internal/client/dom/elements/misc.js index e0fc8d2a19..0a894ba353 100644 --- a/packages/svelte/src/internal/client/dom/elements/misc.js +++ b/packages/svelte/src/internal/client/dom/elements/misc.js @@ -1,6 +1,5 @@ import { hydrating } from '../hydration.js'; import { render_effect } from '../../reactivity/effects.js'; -import { current_block } from '../../runtime.js'; /** * @param {HTMLElement} dom @@ -17,7 +16,6 @@ export function autofocus(dom, value) { dom.focus(); } }, - current_block, true, false ); diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index 8461122a69..210e526d30 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -5,7 +5,7 @@ import { raf } from '../../timing.js'; import { loop } from '../../loop.js'; import { should_intro } from '../../render.js'; import { is_function } from '../../utils.js'; -import { current_each_item_block } from '../blocks/each.js'; +import { current_each_item } from '../blocks/each.js'; import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../constants.js'; import { EFFECT_RAN } from '../../constants.js'; @@ -77,7 +77,7 @@ const linear = (t) => t; * @param {(() => P) | null} get_params */ export function animation(element, get_fn, get_params) { - var block = /** @type {import('#client').EachItem} */ (current_each_item_block); + var item = /** @type {import('#client').EachItem} */ (current_each_item); /** @type {DOMRect} */ var from; @@ -88,7 +88,7 @@ export function animation(element, get_fn, get_params) { /** @type {import('#client').Animation | undefined} */ var animation; - block.a ??= { + item.a ??= { element, measure() { from = this.element.getBoundingClientRect(); @@ -118,7 +118,7 @@ export function animation(element, get_fn, get_params) { // when an animation manager already exists, if the tag changes. in that case, we need to // swap out the element rather than creating a new manager, in case it happened at the same // moment as a reconciliation - block.a.element = element; + item.a.element = element; } /** diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index 8fcd271ecd..76fb609b77 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -5,7 +5,7 @@ import { create_fragment_with_script_from_html, insert } from './reconciler.js'; -import { current_block } from '../runtime.js'; +import { current_effect } from '../runtime.js'; import { is_array } from '../utils.js'; /** @@ -192,7 +192,7 @@ function close_template(dom, is_fragment, anchor) { insert(current, anchor); } - /** @type {import('#client').Block} */ (current_block).d = current; + /** @type {import('#client').Effect} */ (current_effect).dom = current; return current; } diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index ebe1a422cb..d0a09a201b 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -1,7 +1,6 @@ import { DEV } from 'esm-env'; import { check_dirtiness, - current_block, current_component_context, current_effect, current_reaction, @@ -25,20 +24,20 @@ import { } from '../constants.js'; import { set } from './sources.js'; import { noop } from '../../common.js'; +import { remove } from '../dom/reconciler.js'; /** * @param {import('./types.js').EffectType} type * @param {(() => void | (() => void))} fn * @param {boolean} sync - * @param {null | import('#client').Block} block * @param {boolean} init * @returns {import('#client').Effect} */ -function create_effect(type, fn, sync, block = current_block, init = true) { +function create_effect(type, fn, sync, init = true) { /** @type {import('#client').Effect} */ const signal = { parent: current_effect, - block, + dom: null, deps: null, f: type | DIRTY, l: 0, @@ -99,7 +98,7 @@ export function user_effect(fn) { current_component_context !== null && !current_component_context.m; - const effect = create_effect(EFFECT, fn, false, current_block, !defer); + const effect = create_effect(EFFECT, fn, false, !defer); if (defer) { const context = /** @type {import('#client').ComponentContext} */ (current_component_context); @@ -115,7 +114,7 @@ export function user_effect(fn) { * @returns {() => void} */ export function user_root_effect(fn) { - const effect = render_effect(fn, current_block, true); + const effect = render_effect(fn, true); return () => { destroy_effect(effect); }; @@ -216,17 +215,15 @@ export function invalidate_effect(fn) { /** * @param {(() => void)} fn - * @param {any} block - * @param {any} managed - * @param {any} sync + * @param {boolean} managed + * @param {boolean} sync * @returns {import('#client').Effect} */ -export function render_effect(fn, block = current_block, managed = false, sync = true) { +export function render_effect(fn, managed = false, sync = true) { let flags = RENDER_EFFECT; - if (managed) { - flags |= MANAGED; - } - return create_effect(flags, /** @type {any} */ (fn), sync, block); + if (managed) flags |= MANAGED; + + return create_effect(flags, /** @type {any} */ (fn), sync); } /** @@ -245,6 +242,11 @@ export function destroy_effect(effect) { } effect.teardown?.(); + + if (effect.dom !== null) { + remove(effect.dom); + } + effect.ondestroy?.(); // @ts-expect-error @@ -253,7 +255,7 @@ export function destroy_effect(effect) { effect.teardown = effect.ondestroy = effect.ctx = - effect.block = + effect.dom = effect.deps = null; } @@ -269,26 +271,51 @@ export function destroy_effect(effect) { */ export function pause_effect(effect, callback = noop) { /** @type {import('#client').TransitionManager[]} */ - const transitions = []; + var transitions = []; pause_children(effect, transitions, true); - let remaining = transitions.length; + out(transitions, () => { + destroy_effect(effect); + callback(); + }); +} - if (remaining > 0) { - const check = () => { - if (!--remaining) { - destroy_effect(effect); - callback(); - } - }; +/** + * Pause multiple effects simultaneously, and coordinate their + * subsequent destruction. Used in each blocks + * @param {import('#client').Effect[]} effects + * @param {() => void} callback + */ +export function pause_effects(effects, callback = noop) { + /** @type {import('#client').TransitionManager[]} */ + var transitions = []; + + for (var effect of effects) { + pause_children(effect, transitions, true); + } + + out(transitions, () => { + for (var effect of effects) { + destroy_effect(effect); + } + callback(); + }); +} - for (const transition of transitions) { +/** + * @param {import('#client').TransitionManager[]} transitions + * @param {() => void} fn + */ +function out(transitions, fn) { + var remaining = transitions.length; + if (remaining > 0) { + var check = () => --remaining || fn(); + for (var transition of transitions) { transition.out(check); } } else { - destroy_effect(effect); - callback(); + fn(); } } diff --git a/packages/svelte/src/internal/client/reactivity/types.d.ts b/packages/svelte/src/internal/client/reactivity/types.d.ts index c0aceff874..a28b0fefbc 100644 --- a/packages/svelte/src/internal/client/reactivity/types.d.ts +++ b/packages/svelte/src/internal/client/reactivity/types.d.ts @@ -1,4 +1,4 @@ -import type { Block, ComponentContext, Equals, TransitionManager } from '#client'; +import type { Block, ComponentContext, Dom, Equals, TransitionManager } from '#client'; import type { EFFECT, PRE_EFFECT, RENDER_EFFECT } from '../constants'; export type EffectType = typeof EFFECT | typeof PRE_EFFECT | typeof RENDER_EFFECT; @@ -37,8 +37,7 @@ export interface Derived extends Value, Reaction { export interface Effect extends Reaction { parent: Effect | null; - /** The block associated with this effect */ - block: null | Block; + dom: Dom | null; /** The associated component context */ ctx: null | ComponentContext; /** Stuff to do when the effect is destroyed */ diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 7b7f939154..7c3151e773 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -211,40 +211,30 @@ function _mount(Component, options) { should_intro = options.intro ?? false; - /** @type {import('#client').Block} */ - const block = { - // dom - d: null - }; - /** @type {Exports} */ // @ts-expect-error will be defined because the render effect runs synchronously let component = undefined; - const effect = render_effect( - () => { - if (options.context) { - push({}); - /** @type {import('../client/types.js').ComponentContext} */ (current_component_context).c = - options.context; - } - if (!options.props) { - options.props = /** @type {Props} */ ({}); - } - if (options.events) { - // We can't spread the object or else we'd lose the state proxy stuff, if it is one - /** @type {any} */ (options.props).$$events = options.events; - } - component = - // @ts-expect-error the public typings are not what the actual function looks like - Component(options.anchor, options.props) || {}; - if (options.context) { - pop(); - } - }, - block, - true - ); + const effect = render_effect(() => { + if (options.context) { + push({}); + /** @type {import('../client/types.js').ComponentContext} */ (current_component_context).c = + options.context; + } + if (!options.props) { + options.props = /** @type {Props} */ ({}); + } + if (options.events) { + // We can't spread the object or else we'd lose the state proxy stuff, if it is one + /** @type {any} */ (options.props).$$events = options.events; + } + component = + // @ts-expect-error the public typings are not what the actual function looks like + Component(options.anchor, options.props) || {}; + if (options.context) { + pop(); + } + }, true); const bound_event_listener = handle_event_propagation.bind(null, container); const bound_document_event_listener = handle_event_propagation.bind(null, document); @@ -291,7 +281,7 @@ function _mount(Component, options) { container.removeEventListener(event_name, bound_event_listener); } root_event_handles.delete(event_handle); - const dom = block.d; + const dom = effect.dom; if (dom !== null) { remove(dom); } diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 4d89430650..2febac4861 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -107,11 +107,7 @@ export let inspect_fn = null; /** @type {Array} */ let inspect_captured_signals = []; -// Handle rendering tree blocks and anchors -/** @type {null | import('./types.js').Block} */ -export let current_block = null; // Handling runtime component context - /** @type {import('./types.js').ComponentContext | null} */ export let current_component_context = null; @@ -387,13 +383,11 @@ export function execute_effect(signal) { const previous_effect = current_effect; const previous_component_context = current_component_context; - const previous_block = current_block; const component_context = signal.ctx; current_effect = signal; current_component_context = component_context; - current_block = signal.block; try { destroy_children(signal); @@ -403,7 +397,6 @@ export function execute_effect(signal) { } finally { current_effect = previous_effect; current_component_context = previous_component_context; - current_block = previous_block; } if ((signal.f & PRE_EFFECT) !== 0 && current_queued_pre_and_render_effects.length > 0) { @@ -514,7 +507,6 @@ export function schedule_effect(signal, sync) { if (!should_append) { const target_level = signal.l; - const target_block = signal.block; const is_pre_effect = (flags & PRE_EFFECT) !== 0; let target_signal; let target_signal_level; @@ -530,7 +522,7 @@ export function schedule_effect(signal, sync) { is_target_pre_effect = (target_signal.f & PRE_EFFECT) !== 0; if ( target_signal_level < target_level || - target_signal.block !== target_block || + target_signal !== signal || (is_target_pre_effect && !is_pre_effect) ) { i++; diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index d2426ee5d3..0a89b0045a 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -51,10 +51,7 @@ export type TemplateNode = Text | Element | Comment; export type Dom = TemplateNode | TemplateNode[]; -export interface Block { - /** dom */ - d: null | Dom; -} +export interface Block {} export type EachState = { /** flags */ @@ -66,8 +63,6 @@ export type EachState = { export type EachItem = { /** animation manager */ a: AnimationManager | null; - /** dom */ - d: null | Dom; /** effect */ e: Effect; /** item */ diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 248046073c..91c0e2eb5f 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -26,7 +26,6 @@ function run_test(runes: boolean, fn: (runes: boolean) => () => void) { () => { execute = fn(runes); }, - null, true, true );