From 8b263cb611ff48a611a918952fab8f5a98e73994 Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Sun, 1 Jun 2025 19:35:10 +0100 Subject: [PATCH 1/5] add comments and logs --- .../src/internal/client/dom/blocks/if.js | 28 +- packages/svelte/src/internal/client/proxy.js | 5 + .../src/internal/client/reactivity/effects.js | 379 +++++++++++++++++- .../src/internal/client/reactivity/sources.js | 11 + packages/svelte/src/internal/client/render.js | 1 + .../svelte/src/internal/client/runtime.js | 78 +++- 6 files changed, 498 insertions(+), 4 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index bf1098c3f465..c0424195d446 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -10,7 +10,13 @@ import { set_hydrating } from '../hydration.js'; import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js'; -import { HYDRATION_START, HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js'; +import { + FILENAME, + HYDRATION_START, + HYDRATION_START_ELSE, + UNINITIALIZED +} from '../../../../constants.js'; +import { DEV } from 'esm-env'; /** * @param {TemplateNode} node @@ -50,6 +56,16 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { /** @type {boolean | null} */ new_condition, /** @type {null | ((anchor: Node, elseif?: [number,number]) => void)} */ fn ) => { + // if (DEV && new Error().stack?.includes('NestedComponent')) { + // console.debug('update_branch', new_condition, { + // previousCondition: condition, + // conditionChanged: condition !== new_condition, + // hasConsequentEffect: !!consequent_effect, + // hasAlternateEffect: !!alternate_effect, + // fn + // }); + // } + if (condition === (condition = new_condition)) return; /** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ @@ -86,6 +102,10 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { } } + // if (new Error().stack?.includes('NestedComponent')) { + // // debugger; + // } + if (condition) { if (consequent_effect) { resume_effect(consequent_effect); @@ -106,6 +126,12 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { } if (consequent_effect) { + // if (DEV) { + // // HERE is the deletion of the dom text node + // if (new Error().stack?.includes('NestedComponent')) { + // // debugger; + // } + // } pause_effect(consequent_effect, () => { consequent_effect = null; }); diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index fd5706eaf270..532aab0db238 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -21,6 +21,8 @@ import { tracing_mode_flag } from '../flags/index.js'; * @returns {T} */ export function proxy(value) { + // console.debug('proxy', value); + // if non-proxyable, or is already a proxy, return `value` if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { return value; @@ -46,12 +48,14 @@ export function proxy(value) { */ var with_parent = (fn) => { var previous_reaction = active_reaction; + // var previous_reaction_sources = reaction_sources; set_active_reaction(reaction); /** @type {T} */ var result = fn(); set_active_reaction(previous_reaction); + // set_active_reaction_sources(previous_reaction_sources); return result; }; @@ -128,6 +132,7 @@ export function proxy(value) { var s = sources.get(prop); var exists = prop in target; + // BREAKPOINT // create a source, but only if it's an own property and not a prototype property if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) { s = with_parent(() => source(proxy(exists ? target[prop] : UNINITIALIZED), stack)); diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 36be1ecd0427..e9e00e94988c 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -1,4 +1,4 @@ -/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */ +/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, Reaction, TemplateNode, TransitionManager } from '#client' */ import { check_dirtiness, active_effect, @@ -32,7 +32,10 @@ import { HEAD_EFFECT, MAYBE_DIRTY, EFFECT_HAS_DERIVED, - BOUNDARY_EFFECT + BOUNDARY_EFFECT, + EFFECT_IS_UPDATING, + DISCONNECTED, + LEGACY_DERIVED_PROP } from '#client/constants'; import { set } from './sources.js'; import * as e from '../errors.js'; @@ -41,6 +44,372 @@ import { define_property } from '../../shared/utils.js'; import { get_next_sibling } from '../dom/operations.js'; import { derived } from './deriveds.js'; import { component_context, dev_current_component_function } from '../context.js'; +import { FILENAME } from '../../../constants.js'; + +/** + * Get human-readable information about an effect for debugging + * @param {Effect | null} effect + * @returns {{ + * type: string, + * typeFlags: string, + * typeNumeric: number, + * typeBinary: string, + * status: string, + * parent: string, + * parentChain: string, + * component: string, + * hasChildren: boolean, + * hasDeps: number, + * hasNodes: boolean + * }} + */ +export function get_effect_debug_info(effect) { + if (!effect) + return { + type: 'NO_EFFECT', + typeFlags: '0x0 (0)', + typeNumeric: 0, + typeBinary: '00000000', + status: 'NONE', + parent: 'NO_PARENT', + parentChain: 'NONE', + component: 'NO_COMPONENT', + hasChildren: false, + hasDeps: 0, + hasNodes: false + }; + + const flags = effect.f; + + // Core effect types + const effectTypes = []; + const statusFlags = []; + + // Core effect types + if (flags & DERIVED) effectTypes.push('DERIVED'); + if (flags & EFFECT) effectTypes.push('EFFECT'); + if (flags & RENDER_EFFECT) effectTypes.push('RENDER_EFFECT'); + if (flags & BLOCK_EFFECT) effectTypes.push('BLOCK_EFFECT'); + if (flags & BRANCH_EFFECT) effectTypes.push('BRANCH_EFFECT'); + if (flags & ROOT_EFFECT) effectTypes.push('ROOT_EFFECT'); + if (flags & BOUNDARY_EFFECT) effectTypes.push('BOUNDARY_EFFECT'); + if (flags & INSPECT_EFFECT) effectTypes.push('INSPECT_EFFECT'); + if (flags & HEAD_EFFECT) effectTypes.push('HEAD_EFFECT'); + + // Status flags + if (flags & UNOWNED) statusFlags.push('UNOWNED'); + if (flags & DISCONNECTED) statusFlags.push('DISCONNECTED'); + if (flags & CLEAN) statusFlags.push('CLEAN'); + if (flags & DIRTY) statusFlags.push('DIRTY'); + if (flags & MAYBE_DIRTY) statusFlags.push('MAYBE_DIRTY'); + if (flags & INERT) statusFlags.push('INERT'); + if (flags & DESTROYED) statusFlags.push('DESTROYED'); + if (flags & EFFECT_RAN) statusFlags.push('EFFECT_RAN'); + if (flags & EFFECT_TRANSPARENT) statusFlags.push('EFFECT_TRANSPARENT'); + if (flags & LEGACY_DERIVED_PROP) statusFlags.push('LEGACY_DERIVED_PROP'); + if (flags & EFFECT_HAS_DERIVED) statusFlags.push('EFFECT_HAS_DERIVED'); + if (flags & EFFECT_IS_UPDATING) statusFlags.push('EFFECT_IS_UPDATING'); + + // Build parent chain + const parentChain = []; + let current = effect.parent; + let depth = 0; + + while (current && depth < 5) { + // Limit depth to prevent infinite loops + const parentTypes = []; + const parentFlags = current.f; + + if (parentFlags & DERIVED) parentTypes.push('DERIVED'); + if (parentFlags & EFFECT) parentTypes.push('EFFECT'); + if (parentFlags & RENDER_EFFECT) parentTypes.push('RENDER'); + if (parentFlags & BLOCK_EFFECT) parentTypes.push('BLOCK'); + if (parentFlags & BRANCH_EFFECT) parentTypes.push('BRANCH'); + if (parentFlags & ROOT_EFFECT) parentTypes.push('ROOT'); + if (parentFlags & BOUNDARY_EFFECT) parentTypes.push('BOUNDARY'); + if (parentFlags & INSPECT_EFFECT) parentTypes.push('INSPECT'); + if (parentFlags & HEAD_EFFECT) parentTypes.push('HEAD'); + + parentChain.push(parentTypes.length > 0 ? parentTypes.join('+') : 'UNKNOWN'); + current = current.parent; + depth++; + } + + return { + type: effectTypes.length > 0 ? effectTypes.join(' + ') : 'UNKNOWN', + typeFlags: `0x${flags.toString(16)} (${flags})`, + typeNumeric: flags, + typeBinary: flags.toString(2).padStart(8, '0'), + status: statusFlags.join(' + ') || 'NONE', + parent: effect.parent ? 'HAS_PARENT' : 'NO_PARENT', + parentChain: parentChain.length > 0 ? parentChain.join(' → ') : 'NO_PARENTS', + component: effect.component_function?.name || 'NO_COMPONENT', + hasChildren: !!effect.first, + hasDeps: effect.deps ? effect.deps.length : 0, + hasNodes: !!effect.nodes_start + }; +} + +/** + * Decode reaction/effect flags (the 'f' property) into human-readable format + * The 'f' property contains bitwise flags that represent: + * - Type of effect (RENDER_EFFECT, BRANCH_EFFECT, etc.) + * - Status flags (DIRTY, CLEAN, MAYBE_DIRTY, etc.) + * - Behavior flags (UNOWNED, INERT, etc.) + * + * @param {number} flags - The flags value (reaction.f or effect.f) + * @returns {{ + * numeric: number, + * hex: string, + * binary: string, + * types: string[], + * status: string[], + * behavior: string[], + * all: string[], + * summary: string + * }} + */ +export function decode_reaction_flags(flags) { + const types = []; + const status = []; + const behavior = []; + + // Core effect/reaction types + if (flags & DERIVED) types.push('DERIVED'); + if (flags & EFFECT) types.push('EFFECT'); + if (flags & RENDER_EFFECT) types.push('RENDER_EFFECT'); + if (flags & BLOCK_EFFECT) types.push('BLOCK_EFFECT'); + if (flags & BRANCH_EFFECT) types.push('BRANCH_EFFECT'); + if (flags & ROOT_EFFECT) types.push('ROOT_EFFECT'); + if (flags & BOUNDARY_EFFECT) types.push('BOUNDARY_EFFECT'); + if (flags & INSPECT_EFFECT) types.push('INSPECT_EFFECT'); + if (flags & HEAD_EFFECT) types.push('HEAD_EFFECT'); + + // Status flags (mutually exclusive in some cases) + if (flags & CLEAN) status.push('CLEAN'); + if (flags & DIRTY) status.push('DIRTY'); + if (flags & MAYBE_DIRTY) status.push('MAYBE_DIRTY'); + if (flags & DESTROYED) status.push('DESTROYED'); + if (flags & EFFECT_RAN) status.push('EFFECT_RAN'); + if (flags & EFFECT_IS_UPDATING) status.push('EFFECT_IS_UPDATING'); + + // Behavior flags + if (flags & UNOWNED) behavior.push('UNOWNED'); + if (flags & DISCONNECTED) behavior.push('DISCONNECTED'); + if (flags & INERT) behavior.push('INERT'); + if (flags & EFFECT_TRANSPARENT) behavior.push('EFFECT_TRANSPARENT'); + if (flags & LEGACY_DERIVED_PROP) behavior.push('LEGACY_DERIVED_PROP'); + if (flags & EFFECT_HAS_DERIVED) behavior.push('EFFECT_HAS_DERIVED'); + + const all = [...types, ...status, ...behavior]; + + return { + numeric: flags, + hex: `0x${flags.toString(16).toUpperCase()}`, + binary: flags.toString(2).padStart(24, '0'), // 24 bits for better readability + types, + status, + behavior, + all, + summary: all.length > 0 ? all.join(' + ') : 'NO_FLAGS' + }; +} + +/** + * Log the operation being performed on reaction flags for debugging + * Usage: log_flag_operation(reaction, 'f ^= EFFECT_IS_UPDATING', EFFECT_IS_UPDATING) + * + * @param {any} reaction - The reaction/effect object + * @param {string} operation - Description of the operation (e.g., 'f ^= EFFECT_IS_UPDATING') + * @param {number} flagValue - The flag value being operated on + */ +export function log_flag_operation(reaction, operation, flagValue) { + if (!DEV) return; + + const beforeFlags = decode_reaction_flags(reaction.f); + const operationFlag = decode_reaction_flags(flagValue); + + // Create flags string with format "FLAG_NAME (number) + FLAG_NAME (number)" + const flagsString = + beforeFlags.all + .map((flag) => { + const flagNumeric = getFlagNumericValue(flag); + return `${flag} (${flagNumeric})`; + }) + .join(' + ') || 'NO_FLAGS (0)'; + + // Create operation description + const operationType = operation.includes('^=') + ? 'toggle flag' + : operation.includes('|=') + ? 'add flag' + : operation.includes('&=') + ? 'remove flag' + : 'set flag'; + + console.debug(`Flag operation: ${operation}`, { + flags: flagsString, + operation: `(${operation}) ${operationType}`, + operationFlag: `${operationFlag.summary} (${flagValue})` + }); +} + +/** + * Helper to get numeric value for a flag name + * @param {string} flagName + * @returns {number} + */ +function getFlagNumericValue(flagName) { + const flagMap = /** @type {Record} */ ({ + DERIVED: DERIVED, + EFFECT: EFFECT, + RENDER_EFFECT: RENDER_EFFECT, + BLOCK_EFFECT: BLOCK_EFFECT, + BRANCH_EFFECT: BRANCH_EFFECT, + ROOT_EFFECT: ROOT_EFFECT, + BOUNDARY_EFFECT: BOUNDARY_EFFECT, + INSPECT_EFFECT: INSPECT_EFFECT, + HEAD_EFFECT: HEAD_EFFECT, + CLEAN: CLEAN, + DIRTY: DIRTY, + MAYBE_DIRTY: MAYBE_DIRTY, + DESTROYED: DESTROYED, + EFFECT_RAN: EFFECT_RAN, + EFFECT_IS_UPDATING: EFFECT_IS_UPDATING, + UNOWNED: UNOWNED, + DISCONNECTED: DISCONNECTED, + INERT: INERT, + EFFECT_TRANSPARENT: EFFECT_TRANSPARENT, + LEGACY_DERIVED_PROP: LEGACY_DERIVED_PROP, + EFFECT_HAS_DERIVED: EFFECT_HAS_DERIVED + }); + return flagMap[flagName] || 0; +} + +/** + * Log effect processing information in a simplified format + * @param {Effect} effect - The effect being processed + */ +export function get_effect_info(effect) { + if (!DEV) return; + + const flags = effect.f; + const effectInfo = decode_reaction_flags(flags); + + return { + effectType: effectInfo.summary, + component: effect.component_function?.[FILENAME] || 'NO_COMPONENT', + effect: effect + }; +} + +/** + * Build a tree representation of effects starting from a root effect + * @param {Effect} root - The root effect to start traversal from + * @returns {{effectType: string, component: string, effect: Effect, children: any[]} | null} Tree representation + */ +export function get_effect_tree(root) { + if (!root) return null; + + const map = new Map(); + + // Create root object + const rootObj = { + effectType: decode_reaction_flags(root.f).summary, + component: root.component_function?.[FILENAME] || 'NO_COMPONENT', + effect: root, + children: [] + }; + map.set(root, rootObj); + + // Start traversal from root's first child + let effect = root.first; + + while (effect != null) { + // Create object for current effect + const effectObj = { + effectType: decode_reaction_flags(effect.f).summary, + component: effect.component_function?.[FILENAME] || 'NO_COMPONENT', + effect: effect, + children: [] + }; + map.set(effect, effectObj); + + // Add to parent's children array + if (effect.parent && map.has(effect.parent)) { + const parentObj = map.get(effect.parent); + parentObj.children.push(effectObj); + } + + // Navigate to children first (depth-first traversal) + const child = effect.first; + if (child !== null) { + effect = child; + continue; + } + + // Then navigate to siblings + let parent = effect.parent; + effect = effect.next; + + // If no sibling, go up to parent and try its sibling + while (effect === null && parent !== null) { + effect = parent.next; + parent = parent.parent; + } + } + + return rootObj; +} + +/** + * Get all parent effects of a given effect in an array + * @param {Effect} effect - The effect to get parents for + * @returns {Array<{effectType: string, component: string, effect: Effect}>} Array of parent effects + */ +export function get_effect_parents(effect) { + if (!effect) return []; + + const parents = []; + let current = effect.parent; + + while (current != null) { + const parentObj = { + effectType: decode_reaction_flags(current.f).summary, + component: current.component_function?.[FILENAME] || 'NO_COMPONENT', + effect: current + }; + parents.push(parentObj); + current = current.parent; + } + + return parents; +} + +/** + * Comprehensive effect debugging information combining all logging utilities + * @param {Effect} effect - The effect to get debugging info for + * @returns {{ + * info: {effectType: string, component: string, effect: Effect} | null, + * tree: {effectType: string, component: string, effect: Effect, children: any[]} | null, + * parents: Array<{effectType: string, component: string, effect: Effect}> + * }} Combined debugging information + */ +export function get_comprehensive_effect_info(effect) { + if (!DEV || !effect) { + return { + info: null, + tree: null, + parents: [] + }; + } + + return { + info: get_effect_info(effect) || null, + tree: get_effect_tree(effect), + parents: get_effect_parents(effect) + }; +} /** * @param {'$effect' | '$effect.pre' | '$inspect'} rune @@ -109,6 +478,12 @@ function create_effect(type, fn, sync, push = true) { wv: 0 }; + if (DEV) { + // if (effect.component_function?.[FILENAME].includes('NestedComponent')) { + // console.debug('create_effect', get_comprehensive_effect_info(effect)); + // } + } + if (DEV) { effect.component_function = dev_current_component_function; } diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 9d2ad2baee4e..426eeda214f1 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -35,6 +35,7 @@ import { get_stack } from '../dev/tracing.js'; import { component_context, is_runes } from '../context.js'; import { proxy } from '../proxy.js'; import { execute_derived } from './deriveds.js'; +import { get_comprehensive_effect_info } from './effects.js'; export let inspect_effects = new Set(); export const old_values = new Map(); @@ -180,6 +181,15 @@ export function internal_set(source, value) { source.wv = increment_write_version(); + // if (DEV && new Error().stack?.includes('service.svelte.ts')) { + // console.debug('internal_set', source, value); + // source.reactions?.forEach((reaction) => { + // const reaction_as_any = /** @type {any} */ (reaction); + // const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); + // console.debug('internal_set reaction', get_comprehensive_effect_info(reaction_as_effect)); + // }); + // // debugger; + // } mark_reactions(source, DIRTY); // It's possible that the current reaction might not have up-to-date dependencies @@ -261,6 +271,7 @@ function mark_reactions(signal, status) { var runes = is_runes(); var length = reactions.length; + // BREAKPOINT for (var i = 0; i < length; i++) { var reaction = reactions[i]; var flags = reaction.f; diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 3256fe827410..48cb5ad839d3 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -49,6 +49,7 @@ export function set_should_intro(value) { * @returns {void} */ export function set_text(text, value) { + // debugger; // For objects, we apply string coercion (which might make things like $state array references in the template reactive) before diffing var str = value == null ? '' : typeof value === 'object' ? value + '' : value; // @ts-expect-error diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index d790c0ad145a..36bac755606f 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -5,7 +5,10 @@ import { destroy_block_effect_children, destroy_effect_children, execute_effect_teardown, - unlink_effect + unlink_effect, + decode_reaction_flags, + log_flag_operation, + get_comprehensive_effect_info } from './reactivity/effects.js'; import { EFFECT, @@ -76,6 +79,11 @@ export let untracking = false; /** @param {null | Reaction} reaction */ export function set_active_reaction(reaction) { + const reaction_as_any = /** @type {any} */ (reaction); + const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); + if (DEV && reaction_as_effect?.component_function?.[FILENAME].includes('App_15870.svelte')) { + console.trace('set_active_reaction', get_comprehensive_effect_info(reaction_as_effect)); + } active_reaction = reaction; } @@ -97,6 +105,17 @@ export let reaction_sources = null; /** @param {Value} value */ export function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { + if (DEV && new Error().stack?.includes('NestedComponent')) { + const active_reaction_as_any = /** @type {any} */ (active_reaction); + const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); + console.debug('push_reaction_value value', value); + console.debug( + 'push_reaction_value active_reaction', + get_comprehensive_effect_info(active_reaction_as_effect) + ); + debugger; + } + if (reaction_sources === null) { reaction_sources = [value]; } else { @@ -403,6 +422,18 @@ export function update_reaction(reaction) { (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; + const active_reaction_as_any = /** @type {any} */ (active_reaction); + const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); + if ( + DEV && + active_reaction_as_effect?.component_function?.[FILENAME].includes('NestedComponent.svelte') + ) { + console.debug( + 'update_reaction active_reaction', + get_comprehensive_effect_info(active_reaction_as_effect) + ); + } + reaction_sources = null; set_component_context(reaction.ctx); untracking = false; @@ -411,9 +442,20 @@ export function update_reaction(reaction) { reaction.f |= EFFECT_IS_UPDATING; try { + if (DEV) { + const reaction_as_any = /** @type {any} */ (reaction); + const reaction_as_an_effect = /** @type {Effect} */ (reaction_as_any); + + if (reaction_as_an_effect.component_function?.[FILENAME].includes('NestedComponent')) { + console.debug('update_reaction', get_comprehensive_effect_info(reaction_as_an_effect)); + // debugger; + } + } + var result = /** @type {Function} */ (0, reaction.fn)(); var deps = reaction.deps; + // BREAKPOINT if (new_deps !== null) { var i; @@ -774,6 +816,14 @@ function process_effects(root) { var is_branch = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) !== 0; var is_skippable_branch = is_branch && (flags & CLEAN) !== 0; + // Log each effect being processed + if (DEV) { + if (effect.component_function?.[FILENAME].includes('NestedComponent')) { + console.debug('process_effects', get_comprehensive_effect_info(effect)); + // debugger; + } + } + if (!is_skippable_branch && (flags & INERT) === 0) { if ((flags & EFFECT) !== 0) { effects.push(effect); @@ -864,8 +914,34 @@ export function get(signal) { captured_signals.add(signal); } + if (DEV && new Error().stack?.includes('NestedComponent')) { + // console.debug('get() signal', signal); + // const active_reaction_as_any = /** @type {any} */ (active_reaction); + // const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); + // console.debug( + // 'get() signal active_reaction', + // get_comprehensive_effect_info(active_reaction_as_effect) + // ); + // reaction_sources?.forEach((reaction) => { + // const reaction_as_any = /** @type {any} */ (reaction); + // const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); + // console.debug('get() signal reaction', get_comprehensive_effect_info(reaction_as_effect)); + // }); + // debugger; + } + // Register the dependency on the current reaction signal. if (active_reaction !== null && !untracking) { + const active_reaction_as_any = /** @type {any} */ (active_reaction); + const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); + if (DEV) { + // console.debug( + // 'get() signal active_reaction', + // get_comprehensive_effect_info(active_reaction_as_effect) + // ); + } + + // BREAKPOINT if (!reaction_sources?.includes(signal)) { var deps = active_reaction.deps; if (signal.rv < read_version) { From 6fe00fab9dcdfbb983d267e713264cc918295175 Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Mon, 2 Jun 2025 16:56:46 +0100 Subject: [PATCH 2/5] Revert "add comments and logs" This reverts commit a537f6a1ab7f74ab6e397366f37b50af38907ba0. --- .../src/internal/client/dom/blocks/if.js | 28 +- packages/svelte/src/internal/client/proxy.js | 5 - .../src/internal/client/reactivity/effects.js | 379 +----------------- .../src/internal/client/reactivity/sources.js | 11 - packages/svelte/src/internal/client/render.js | 1 - .../svelte/src/internal/client/runtime.js | 78 +--- 6 files changed, 4 insertions(+), 498 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index c0424195d446..bf1098c3f465 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -10,13 +10,7 @@ import { set_hydrating } from '../hydration.js'; import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js'; -import { - FILENAME, - HYDRATION_START, - HYDRATION_START_ELSE, - UNINITIALIZED -} from '../../../../constants.js'; -import { DEV } from 'esm-env'; +import { HYDRATION_START, HYDRATION_START_ELSE, UNINITIALIZED } from '../../../../constants.js'; /** * @param {TemplateNode} node @@ -56,16 +50,6 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { /** @type {boolean | null} */ new_condition, /** @type {null | ((anchor: Node, elseif?: [number,number]) => void)} */ fn ) => { - // if (DEV && new Error().stack?.includes('NestedComponent')) { - // console.debug('update_branch', new_condition, { - // previousCondition: condition, - // conditionChanged: condition !== new_condition, - // hasConsequentEffect: !!consequent_effect, - // hasAlternateEffect: !!alternate_effect, - // fn - // }); - // } - if (condition === (condition = new_condition)) return; /** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ @@ -102,10 +86,6 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { } } - // if (new Error().stack?.includes('NestedComponent')) { - // // debugger; - // } - if (condition) { if (consequent_effect) { resume_effect(consequent_effect); @@ -126,12 +106,6 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { } if (consequent_effect) { - // if (DEV) { - // // HERE is the deletion of the dom text node - // if (new Error().stack?.includes('NestedComponent')) { - // // debugger; - // } - // } pause_effect(consequent_effect, () => { consequent_effect = null; }); diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index 532aab0db238..fd5706eaf270 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -21,8 +21,6 @@ import { tracing_mode_flag } from '../flags/index.js'; * @returns {T} */ export function proxy(value) { - // console.debug('proxy', value); - // if non-proxyable, or is already a proxy, return `value` if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { return value; @@ -48,14 +46,12 @@ export function proxy(value) { */ var with_parent = (fn) => { var previous_reaction = active_reaction; - // var previous_reaction_sources = reaction_sources; set_active_reaction(reaction); /** @type {T} */ var result = fn(); set_active_reaction(previous_reaction); - // set_active_reaction_sources(previous_reaction_sources); return result; }; @@ -132,7 +128,6 @@ export function proxy(value) { var s = sources.get(prop); var exists = prop in target; - // BREAKPOINT // create a source, but only if it's an own property and not a prototype property if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) { s = with_parent(() => source(proxy(exists ? target[prop] : UNINITIALIZED), stack)); diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index e9e00e94988c..36be1ecd0427 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -1,4 +1,4 @@ -/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, Reaction, TemplateNode, TransitionManager } from '#client' */ +/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */ import { check_dirtiness, active_effect, @@ -32,10 +32,7 @@ import { HEAD_EFFECT, MAYBE_DIRTY, EFFECT_HAS_DERIVED, - BOUNDARY_EFFECT, - EFFECT_IS_UPDATING, - DISCONNECTED, - LEGACY_DERIVED_PROP + BOUNDARY_EFFECT } from '#client/constants'; import { set } from './sources.js'; import * as e from '../errors.js'; @@ -44,372 +41,6 @@ import { define_property } from '../../shared/utils.js'; import { get_next_sibling } from '../dom/operations.js'; import { derived } from './deriveds.js'; import { component_context, dev_current_component_function } from '../context.js'; -import { FILENAME } from '../../../constants.js'; - -/** - * Get human-readable information about an effect for debugging - * @param {Effect | null} effect - * @returns {{ - * type: string, - * typeFlags: string, - * typeNumeric: number, - * typeBinary: string, - * status: string, - * parent: string, - * parentChain: string, - * component: string, - * hasChildren: boolean, - * hasDeps: number, - * hasNodes: boolean - * }} - */ -export function get_effect_debug_info(effect) { - if (!effect) - return { - type: 'NO_EFFECT', - typeFlags: '0x0 (0)', - typeNumeric: 0, - typeBinary: '00000000', - status: 'NONE', - parent: 'NO_PARENT', - parentChain: 'NONE', - component: 'NO_COMPONENT', - hasChildren: false, - hasDeps: 0, - hasNodes: false - }; - - const flags = effect.f; - - // Core effect types - const effectTypes = []; - const statusFlags = []; - - // Core effect types - if (flags & DERIVED) effectTypes.push('DERIVED'); - if (flags & EFFECT) effectTypes.push('EFFECT'); - if (flags & RENDER_EFFECT) effectTypes.push('RENDER_EFFECT'); - if (flags & BLOCK_EFFECT) effectTypes.push('BLOCK_EFFECT'); - if (flags & BRANCH_EFFECT) effectTypes.push('BRANCH_EFFECT'); - if (flags & ROOT_EFFECT) effectTypes.push('ROOT_EFFECT'); - if (flags & BOUNDARY_EFFECT) effectTypes.push('BOUNDARY_EFFECT'); - if (flags & INSPECT_EFFECT) effectTypes.push('INSPECT_EFFECT'); - if (flags & HEAD_EFFECT) effectTypes.push('HEAD_EFFECT'); - - // Status flags - if (flags & UNOWNED) statusFlags.push('UNOWNED'); - if (flags & DISCONNECTED) statusFlags.push('DISCONNECTED'); - if (flags & CLEAN) statusFlags.push('CLEAN'); - if (flags & DIRTY) statusFlags.push('DIRTY'); - if (flags & MAYBE_DIRTY) statusFlags.push('MAYBE_DIRTY'); - if (flags & INERT) statusFlags.push('INERT'); - if (flags & DESTROYED) statusFlags.push('DESTROYED'); - if (flags & EFFECT_RAN) statusFlags.push('EFFECT_RAN'); - if (flags & EFFECT_TRANSPARENT) statusFlags.push('EFFECT_TRANSPARENT'); - if (flags & LEGACY_DERIVED_PROP) statusFlags.push('LEGACY_DERIVED_PROP'); - if (flags & EFFECT_HAS_DERIVED) statusFlags.push('EFFECT_HAS_DERIVED'); - if (flags & EFFECT_IS_UPDATING) statusFlags.push('EFFECT_IS_UPDATING'); - - // Build parent chain - const parentChain = []; - let current = effect.parent; - let depth = 0; - - while (current && depth < 5) { - // Limit depth to prevent infinite loops - const parentTypes = []; - const parentFlags = current.f; - - if (parentFlags & DERIVED) parentTypes.push('DERIVED'); - if (parentFlags & EFFECT) parentTypes.push('EFFECT'); - if (parentFlags & RENDER_EFFECT) parentTypes.push('RENDER'); - if (parentFlags & BLOCK_EFFECT) parentTypes.push('BLOCK'); - if (parentFlags & BRANCH_EFFECT) parentTypes.push('BRANCH'); - if (parentFlags & ROOT_EFFECT) parentTypes.push('ROOT'); - if (parentFlags & BOUNDARY_EFFECT) parentTypes.push('BOUNDARY'); - if (parentFlags & INSPECT_EFFECT) parentTypes.push('INSPECT'); - if (parentFlags & HEAD_EFFECT) parentTypes.push('HEAD'); - - parentChain.push(parentTypes.length > 0 ? parentTypes.join('+') : 'UNKNOWN'); - current = current.parent; - depth++; - } - - return { - type: effectTypes.length > 0 ? effectTypes.join(' + ') : 'UNKNOWN', - typeFlags: `0x${flags.toString(16)} (${flags})`, - typeNumeric: flags, - typeBinary: flags.toString(2).padStart(8, '0'), - status: statusFlags.join(' + ') || 'NONE', - parent: effect.parent ? 'HAS_PARENT' : 'NO_PARENT', - parentChain: parentChain.length > 0 ? parentChain.join(' → ') : 'NO_PARENTS', - component: effect.component_function?.name || 'NO_COMPONENT', - hasChildren: !!effect.first, - hasDeps: effect.deps ? effect.deps.length : 0, - hasNodes: !!effect.nodes_start - }; -} - -/** - * Decode reaction/effect flags (the 'f' property) into human-readable format - * The 'f' property contains bitwise flags that represent: - * - Type of effect (RENDER_EFFECT, BRANCH_EFFECT, etc.) - * - Status flags (DIRTY, CLEAN, MAYBE_DIRTY, etc.) - * - Behavior flags (UNOWNED, INERT, etc.) - * - * @param {number} flags - The flags value (reaction.f or effect.f) - * @returns {{ - * numeric: number, - * hex: string, - * binary: string, - * types: string[], - * status: string[], - * behavior: string[], - * all: string[], - * summary: string - * }} - */ -export function decode_reaction_flags(flags) { - const types = []; - const status = []; - const behavior = []; - - // Core effect/reaction types - if (flags & DERIVED) types.push('DERIVED'); - if (flags & EFFECT) types.push('EFFECT'); - if (flags & RENDER_EFFECT) types.push('RENDER_EFFECT'); - if (flags & BLOCK_EFFECT) types.push('BLOCK_EFFECT'); - if (flags & BRANCH_EFFECT) types.push('BRANCH_EFFECT'); - if (flags & ROOT_EFFECT) types.push('ROOT_EFFECT'); - if (flags & BOUNDARY_EFFECT) types.push('BOUNDARY_EFFECT'); - if (flags & INSPECT_EFFECT) types.push('INSPECT_EFFECT'); - if (flags & HEAD_EFFECT) types.push('HEAD_EFFECT'); - - // Status flags (mutually exclusive in some cases) - if (flags & CLEAN) status.push('CLEAN'); - if (flags & DIRTY) status.push('DIRTY'); - if (flags & MAYBE_DIRTY) status.push('MAYBE_DIRTY'); - if (flags & DESTROYED) status.push('DESTROYED'); - if (flags & EFFECT_RAN) status.push('EFFECT_RAN'); - if (flags & EFFECT_IS_UPDATING) status.push('EFFECT_IS_UPDATING'); - - // Behavior flags - if (flags & UNOWNED) behavior.push('UNOWNED'); - if (flags & DISCONNECTED) behavior.push('DISCONNECTED'); - if (flags & INERT) behavior.push('INERT'); - if (flags & EFFECT_TRANSPARENT) behavior.push('EFFECT_TRANSPARENT'); - if (flags & LEGACY_DERIVED_PROP) behavior.push('LEGACY_DERIVED_PROP'); - if (flags & EFFECT_HAS_DERIVED) behavior.push('EFFECT_HAS_DERIVED'); - - const all = [...types, ...status, ...behavior]; - - return { - numeric: flags, - hex: `0x${flags.toString(16).toUpperCase()}`, - binary: flags.toString(2).padStart(24, '0'), // 24 bits for better readability - types, - status, - behavior, - all, - summary: all.length > 0 ? all.join(' + ') : 'NO_FLAGS' - }; -} - -/** - * Log the operation being performed on reaction flags for debugging - * Usage: log_flag_operation(reaction, 'f ^= EFFECT_IS_UPDATING', EFFECT_IS_UPDATING) - * - * @param {any} reaction - The reaction/effect object - * @param {string} operation - Description of the operation (e.g., 'f ^= EFFECT_IS_UPDATING') - * @param {number} flagValue - The flag value being operated on - */ -export function log_flag_operation(reaction, operation, flagValue) { - if (!DEV) return; - - const beforeFlags = decode_reaction_flags(reaction.f); - const operationFlag = decode_reaction_flags(flagValue); - - // Create flags string with format "FLAG_NAME (number) + FLAG_NAME (number)" - const flagsString = - beforeFlags.all - .map((flag) => { - const flagNumeric = getFlagNumericValue(flag); - return `${flag} (${flagNumeric})`; - }) - .join(' + ') || 'NO_FLAGS (0)'; - - // Create operation description - const operationType = operation.includes('^=') - ? 'toggle flag' - : operation.includes('|=') - ? 'add flag' - : operation.includes('&=') - ? 'remove flag' - : 'set flag'; - - console.debug(`Flag operation: ${operation}`, { - flags: flagsString, - operation: `(${operation}) ${operationType}`, - operationFlag: `${operationFlag.summary} (${flagValue})` - }); -} - -/** - * Helper to get numeric value for a flag name - * @param {string} flagName - * @returns {number} - */ -function getFlagNumericValue(flagName) { - const flagMap = /** @type {Record} */ ({ - DERIVED: DERIVED, - EFFECT: EFFECT, - RENDER_EFFECT: RENDER_EFFECT, - BLOCK_EFFECT: BLOCK_EFFECT, - BRANCH_EFFECT: BRANCH_EFFECT, - ROOT_EFFECT: ROOT_EFFECT, - BOUNDARY_EFFECT: BOUNDARY_EFFECT, - INSPECT_EFFECT: INSPECT_EFFECT, - HEAD_EFFECT: HEAD_EFFECT, - CLEAN: CLEAN, - DIRTY: DIRTY, - MAYBE_DIRTY: MAYBE_DIRTY, - DESTROYED: DESTROYED, - EFFECT_RAN: EFFECT_RAN, - EFFECT_IS_UPDATING: EFFECT_IS_UPDATING, - UNOWNED: UNOWNED, - DISCONNECTED: DISCONNECTED, - INERT: INERT, - EFFECT_TRANSPARENT: EFFECT_TRANSPARENT, - LEGACY_DERIVED_PROP: LEGACY_DERIVED_PROP, - EFFECT_HAS_DERIVED: EFFECT_HAS_DERIVED - }); - return flagMap[flagName] || 0; -} - -/** - * Log effect processing information in a simplified format - * @param {Effect} effect - The effect being processed - */ -export function get_effect_info(effect) { - if (!DEV) return; - - const flags = effect.f; - const effectInfo = decode_reaction_flags(flags); - - return { - effectType: effectInfo.summary, - component: effect.component_function?.[FILENAME] || 'NO_COMPONENT', - effect: effect - }; -} - -/** - * Build a tree representation of effects starting from a root effect - * @param {Effect} root - The root effect to start traversal from - * @returns {{effectType: string, component: string, effect: Effect, children: any[]} | null} Tree representation - */ -export function get_effect_tree(root) { - if (!root) return null; - - const map = new Map(); - - // Create root object - const rootObj = { - effectType: decode_reaction_flags(root.f).summary, - component: root.component_function?.[FILENAME] || 'NO_COMPONENT', - effect: root, - children: [] - }; - map.set(root, rootObj); - - // Start traversal from root's first child - let effect = root.first; - - while (effect != null) { - // Create object for current effect - const effectObj = { - effectType: decode_reaction_flags(effect.f).summary, - component: effect.component_function?.[FILENAME] || 'NO_COMPONENT', - effect: effect, - children: [] - }; - map.set(effect, effectObj); - - // Add to parent's children array - if (effect.parent && map.has(effect.parent)) { - const parentObj = map.get(effect.parent); - parentObj.children.push(effectObj); - } - - // Navigate to children first (depth-first traversal) - const child = effect.first; - if (child !== null) { - effect = child; - continue; - } - - // Then navigate to siblings - let parent = effect.parent; - effect = effect.next; - - // If no sibling, go up to parent and try its sibling - while (effect === null && parent !== null) { - effect = parent.next; - parent = parent.parent; - } - } - - return rootObj; -} - -/** - * Get all parent effects of a given effect in an array - * @param {Effect} effect - The effect to get parents for - * @returns {Array<{effectType: string, component: string, effect: Effect}>} Array of parent effects - */ -export function get_effect_parents(effect) { - if (!effect) return []; - - const parents = []; - let current = effect.parent; - - while (current != null) { - const parentObj = { - effectType: decode_reaction_flags(current.f).summary, - component: current.component_function?.[FILENAME] || 'NO_COMPONENT', - effect: current - }; - parents.push(parentObj); - current = current.parent; - } - - return parents; -} - -/** - * Comprehensive effect debugging information combining all logging utilities - * @param {Effect} effect - The effect to get debugging info for - * @returns {{ - * info: {effectType: string, component: string, effect: Effect} | null, - * tree: {effectType: string, component: string, effect: Effect, children: any[]} | null, - * parents: Array<{effectType: string, component: string, effect: Effect}> - * }} Combined debugging information - */ -export function get_comprehensive_effect_info(effect) { - if (!DEV || !effect) { - return { - info: null, - tree: null, - parents: [] - }; - } - - return { - info: get_effect_info(effect) || null, - tree: get_effect_tree(effect), - parents: get_effect_parents(effect) - }; -} /** * @param {'$effect' | '$effect.pre' | '$inspect'} rune @@ -478,12 +109,6 @@ function create_effect(type, fn, sync, push = true) { wv: 0 }; - if (DEV) { - // if (effect.component_function?.[FILENAME].includes('NestedComponent')) { - // console.debug('create_effect', get_comprehensive_effect_info(effect)); - // } - } - if (DEV) { effect.component_function = dev_current_component_function; } diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 426eeda214f1..9d2ad2baee4e 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -35,7 +35,6 @@ import { get_stack } from '../dev/tracing.js'; import { component_context, is_runes } from '../context.js'; import { proxy } from '../proxy.js'; import { execute_derived } from './deriveds.js'; -import { get_comprehensive_effect_info } from './effects.js'; export let inspect_effects = new Set(); export const old_values = new Map(); @@ -181,15 +180,6 @@ export function internal_set(source, value) { source.wv = increment_write_version(); - // if (DEV && new Error().stack?.includes('service.svelte.ts')) { - // console.debug('internal_set', source, value); - // source.reactions?.forEach((reaction) => { - // const reaction_as_any = /** @type {any} */ (reaction); - // const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); - // console.debug('internal_set reaction', get_comprehensive_effect_info(reaction_as_effect)); - // }); - // // debugger; - // } mark_reactions(source, DIRTY); // It's possible that the current reaction might not have up-to-date dependencies @@ -271,7 +261,6 @@ function mark_reactions(signal, status) { var runes = is_runes(); var length = reactions.length; - // BREAKPOINT for (var i = 0; i < length; i++) { var reaction = reactions[i]; var flags = reaction.f; diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 48cb5ad839d3..3256fe827410 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -49,7 +49,6 @@ export function set_should_intro(value) { * @returns {void} */ export function set_text(text, value) { - // debugger; // For objects, we apply string coercion (which might make things like $state array references in the template reactive) before diffing var str = value == null ? '' : typeof value === 'object' ? value + '' : value; // @ts-expect-error diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 36bac755606f..d790c0ad145a 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -5,10 +5,7 @@ import { destroy_block_effect_children, destroy_effect_children, execute_effect_teardown, - unlink_effect, - decode_reaction_flags, - log_flag_operation, - get_comprehensive_effect_info + unlink_effect } from './reactivity/effects.js'; import { EFFECT, @@ -79,11 +76,6 @@ export let untracking = false; /** @param {null | Reaction} reaction */ export function set_active_reaction(reaction) { - const reaction_as_any = /** @type {any} */ (reaction); - const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); - if (DEV && reaction_as_effect?.component_function?.[FILENAME].includes('App_15870.svelte')) { - console.trace('set_active_reaction', get_comprehensive_effect_info(reaction_as_effect)); - } active_reaction = reaction; } @@ -105,17 +97,6 @@ export let reaction_sources = null; /** @param {Value} value */ export function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { - if (DEV && new Error().stack?.includes('NestedComponent')) { - const active_reaction_as_any = /** @type {any} */ (active_reaction); - const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); - console.debug('push_reaction_value value', value); - console.debug( - 'push_reaction_value active_reaction', - get_comprehensive_effect_info(active_reaction_as_effect) - ); - debugger; - } - if (reaction_sources === null) { reaction_sources = [value]; } else { @@ -422,18 +403,6 @@ export function update_reaction(reaction) { (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; - const active_reaction_as_any = /** @type {any} */ (active_reaction); - const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); - if ( - DEV && - active_reaction_as_effect?.component_function?.[FILENAME].includes('NestedComponent.svelte') - ) { - console.debug( - 'update_reaction active_reaction', - get_comprehensive_effect_info(active_reaction_as_effect) - ); - } - reaction_sources = null; set_component_context(reaction.ctx); untracking = false; @@ -442,20 +411,9 @@ export function update_reaction(reaction) { reaction.f |= EFFECT_IS_UPDATING; try { - if (DEV) { - const reaction_as_any = /** @type {any} */ (reaction); - const reaction_as_an_effect = /** @type {Effect} */ (reaction_as_any); - - if (reaction_as_an_effect.component_function?.[FILENAME].includes('NestedComponent')) { - console.debug('update_reaction', get_comprehensive_effect_info(reaction_as_an_effect)); - // debugger; - } - } - var result = /** @type {Function} */ (0, reaction.fn)(); var deps = reaction.deps; - // BREAKPOINT if (new_deps !== null) { var i; @@ -816,14 +774,6 @@ function process_effects(root) { var is_branch = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) !== 0; var is_skippable_branch = is_branch && (flags & CLEAN) !== 0; - // Log each effect being processed - if (DEV) { - if (effect.component_function?.[FILENAME].includes('NestedComponent')) { - console.debug('process_effects', get_comprehensive_effect_info(effect)); - // debugger; - } - } - if (!is_skippable_branch && (flags & INERT) === 0) { if ((flags & EFFECT) !== 0) { effects.push(effect); @@ -914,34 +864,8 @@ export function get(signal) { captured_signals.add(signal); } - if (DEV && new Error().stack?.includes('NestedComponent')) { - // console.debug('get() signal', signal); - // const active_reaction_as_any = /** @type {any} */ (active_reaction); - // const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); - // console.debug( - // 'get() signal active_reaction', - // get_comprehensive_effect_info(active_reaction_as_effect) - // ); - // reaction_sources?.forEach((reaction) => { - // const reaction_as_any = /** @type {any} */ (reaction); - // const reaction_as_effect = /** @type {Effect} */ (reaction_as_any); - // console.debug('get() signal reaction', get_comprehensive_effect_info(reaction_as_effect)); - // }); - // debugger; - } - // Register the dependency on the current reaction signal. if (active_reaction !== null && !untracking) { - const active_reaction_as_any = /** @type {any} */ (active_reaction); - const active_reaction_as_effect = /** @type {Effect} */ (active_reaction_as_any); - if (DEV) { - // console.debug( - // 'get() signal active_reaction', - // get_comprehensive_effect_info(active_reaction_as_effect) - // ); - } - - // BREAKPOINT if (!reaction_sources?.includes(signal)) { var deps = active_reaction.deps; if (signal.rv < read_version) { From 73f74beb7b8299e04bc8ad3b9a40e40cabba39de Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Mon, 2 Jun 2025 15:43:33 +0100 Subject: [PATCH 3/5] fix --- packages/svelte/src/internal/client/proxy.js | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index fd5706eaf270..79cb0f2227f3 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -8,7 +8,7 @@ import { is_array, object_prototype } from '../shared/utils.js'; -import { state as source, set } from './reactivity/sources.js'; +import { source, state, set } from './reactivity/sources.js'; import { STATE_SYMBOL } from '#client/constants'; import { UNINITIALIZED } from '../../constants.js'; import * as e from './errors.js'; @@ -35,7 +35,7 @@ export function proxy(value) { /** @type {Map>} */ var sources = new Map(); var is_proxied_array = is_array(value); - var version = source(0); + var version = state(0); var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null; var reaction = active_reaction; @@ -56,9 +56,9 @@ export function proxy(value) { }; if (is_proxied_array) { - // We need to create the length source eagerly to ensure that + // We need to create the length source (state) eagerly to ensure that // mutations to the array are properly synced with our proxy - sources.set('length', source(/** @type {any[]} */ (value).length, stack)); + sources.set('length', state(/** @type {any[]} */ (value).length, stack)); } return new Proxy(/** @type {any} */ (value), { @@ -79,7 +79,7 @@ export function proxy(value) { var s = sources.get(prop); if (s === undefined) { - s = with_parent(() => source(descriptor.value, stack)); + s = with_parent(() => state(descriptor.value, stack)); sources.set(prop, s); } else { set( @@ -98,7 +98,7 @@ export function proxy(value) { if (prop in target) { sources.set( prop, - with_parent(() => source(UNINITIALIZED, stack)) + with_parent(() => state(UNINITIALIZED, stack)) ); update_version(version); } @@ -178,7 +178,7 @@ export function proxy(value) { (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { - s = with_parent(() => source(has ? proxy(target[prop]) : UNINITIALIZED, stack)); + s = with_parent(() => state(has ? proxy(target[prop]) : UNINITIALIZED, stack)); sources.set(prop, s); } @@ -202,22 +202,22 @@ export function proxy(value) { if (other_s !== undefined) { set(other_s, UNINITIALIZED); } else if (i in target) { - // If the item exists in the original, we need to create a uninitialized source, - // else a later read of the property would result in a source being created with + // If the item exists in the original, we need to create a uninitialized source (state), + // else a later read of the property would result in a source (state) being created with // the value of the original item at that index. - other_s = with_parent(() => source(UNINITIALIZED, stack)); + other_s = with_parent(() => state(UNINITIALIZED, stack)); sources.set(i + '', other_s); } } } - // If we haven't yet created a source for this property, we need to ensure + // If we haven't yet created a source (state) for this property, we need to ensure // we do so otherwise if we read it later, then the write won't be tracked and // the heuristics of effects will be different vs if we had read the proxied // object property before writing to that property. if (s === undefined) { if (!has || get_descriptor(target, prop)?.writable) { - s = with_parent(() => source(undefined, stack)); + s = with_parent(() => state(undefined, stack)); set( s, with_parent(() => proxy(value)) From deda7d7dc68b15137697057205556ef869bb857c Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Mon, 2 Jun 2025 15:55:50 +0100 Subject: [PATCH 4/5] Add tests --- .../_config.js | 34 +++++++++++++++++++ .../main.svelte | 22 ++++++++++++ .../module.svelte.js | 19 +++++++++++ .../nested.svelte | 15 ++++++++ 4 files changed, 90 insertions(+) create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js create mode 100644 packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js new file mode 100644 index 000000000000..f3dd65eded06 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, logs }) { + const button = target.querySelector('button'); + + assert.htmlEqual( + target.innerHTML, + ` + +
+

First if block:

+ First: true +

Second if block:

+ Second: true +
+ ` + ); + + flushSync(() => button?.click()); + + assert.htmlEqual( + target.innerHTML, + ` + +
+

First if block:

+

Second if block:

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte new file mode 100644 index 000000000000..0408b6218aba --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte @@ -0,0 +1,22 @@ + + + +
diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js new file mode 100644 index 000000000000..7bb247167036 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js @@ -0,0 +1,19 @@ +import { mount } from 'svelte'; +import Nested from './nested.svelte'; + +export function mountComponentWithContext(target) { + const stateObject = $state({ showText: true }); + + mount(Nested, { + target, + props: {}, + context: new Map([['stateContext', stateObject]]) + }); + + return { + getShowText: () => stateObject.showText, + setShowText: (newShowText) => { + stateObject.showText = newShowText; + } + }; +} diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte new file mode 100644 index 000000000000..92c6d800ae2f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte @@ -0,0 +1,15 @@ + + +

First if block:

+{#if stateObjectFromContext.showText === true} + First: {stateObjectFromContext.showText} +{/if} + +

Second if block:

+{#if stateObjectFromContext.showText === true} + Second: {stateObjectFromContext.showText} +{/if} From f65e6fc2fd0601eb419505fd2cad725e6a9d2381 Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Mon, 2 Jun 2025 17:27:34 +0100 Subject: [PATCH 5/5] Add changeset --- .changeset/swift-oranges-cover.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/swift-oranges-cover.md diff --git a/.changeset/swift-oranges-cover.md b/.changeset/swift-oranges-cover.md new file mode 100644 index 000000000000..fd1b94cfd9b6 --- /dev/null +++ b/.changeset/swift-oranges-cover.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +Fix components mounted via mount() during onMount() that not properly update when using signals provided as input of the mount() function.