From 436a6c3dc48d0336b91da33728b0858c320a86cb Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 13 Dec 2023 02:06:38 +0000 Subject: [PATCH] fix: improve $inspect batching (#9902) * fix: improve $inspect batching * fix dev bug * simplify * simplify --- .changeset/heavy-ears-rule.md | 5 +++ .../svelte/src/internal/client/proxy/proxy.js | 16 ++++++-- .../svelte/src/internal/client/runtime.js | 37 +++++++++++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 .changeset/heavy-ears-rule.md diff --git a/.changeset/heavy-ears-rule.md b/.changeset/heavy-ears-rule.md new file mode 100644 index 0000000000..7dcd27070a --- /dev/null +++ b/.changeset/heavy-ears-rule.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: improve $inspect batching diff --git a/packages/svelte/src/internal/client/proxy/proxy.js b/packages/svelte/src/internal/client/proxy/proxy.js index 4453404dc3..57c2178798 100644 --- a/packages/svelte/src/internal/client/proxy/proxy.js +++ b/packages/svelte/src/internal/client/proxy/proxy.js @@ -7,7 +7,8 @@ import { source, updating_derived, UNINITIALIZED, - mutable_source + mutable_source, + batch_inspect } from '../runtime.js'; import { define_property, @@ -166,8 +167,17 @@ const handler = { metadata.s.set(prop, s); } - const value = s !== undefined ? get(s) : Reflect.get(target, prop, receiver); - return value === UNINITIALIZED ? undefined : value; + if (s !== undefined) { + const value = get(s); + return value === UNINITIALIZED ? undefined : value; + } + + if (DEV) { + if (typeof target[prop] === 'function' && prop !== Symbol.iterator) { + return batch_inspect(target, prop, receiver); + } + } + return Reflect.get(target, prop, receiver); }, getOwnPropertyDescriptor(target, prop) { diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 428c033229..6fb4cc927a 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -37,6 +37,8 @@ let current_scheduler_mode = FLUSH_MICROTASK; // Used for handling scheduling let is_micro_task_queued = false; let is_task_queued = false; +// Used for $inspect +export let is_batching_effect = false; // Handle effect queues @@ -62,8 +64,8 @@ let current_dependencies = null; let current_dependencies_index = 0; /** @type {null | import('./types.js').Signal[]} */ let current_untracked_writes = null; -// Handling capturing of signals from object property getters -let current_should_capture_signal = false; +/** @type {null | import('./types.js').Signal} */ +let last_inspected_signal = null; /** If `true`, `get`ting the signal should not register it as a dependency */ export let current_untracking = false; /** Exists to opt out of the mutation validation for stores which may be set for the first time during a derivation */ @@ -110,6 +112,29 @@ function is_runes(context) { return component_context !== null && component_context.r; } +/** + * @param {import("./proxy/proxy.js").StateObject} target + * @param {string | symbol} prop + * @param {any} receiver + */ +export function batch_inspect(target, prop, receiver) { + const value = Reflect.get(target, prop, receiver); + return function () { + const previously_batching_effect = is_batching_effect; + is_batching_effect = true; + try { + return Reflect.apply(value, receiver, arguments); + } finally { + is_batching_effect = previously_batching_effect; + if (last_inspected_signal !== null) { + // @ts-expect-error + for (const fn of last_inspected_signal.inspect) fn(); + last_inspected_signal = null; + } + } + }; +} + /** * @param {null | import('./types.js').ComponentContext} context_stack_item * @returns {void} @@ -1053,8 +1078,12 @@ export function set_signal_value(signal, value) { // @ts-expect-error if (DEV && signal.inspect) { - // @ts-expect-error - for (const fn of signal.inspect) fn(); + if (is_batching_effect) { + last_inspected_signal = signal; + } else { + // @ts-expect-error + for (const fn of signal.inspect) fn(); + } } } }