From a91e0154d4bc4b0a3209956647f868e518d0acba Mon Sep 17 00:00:00 2001 From: Laszlo Korte Date: Thu, 31 Jul 2025 09:45:52 +0200 Subject: [PATCH] fix: double event processing in Firefox (#16522) (#16527) * Fix double event processing (#16522) Firefox seems to garbage collect event objects during event propagation if no global reference to the event object is kept. That discards the __root marker set on the event object to early, leading to duplicate processing. * minor tweaks --------- Co-authored-by: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> --- .changeset/chilly-bananas-train.md | 5 +++++ .../svelte/src/internal/client/dom/elements/events.js | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 .changeset/chilly-bananas-train.md diff --git a/.changeset/chilly-bananas-train.md b/.changeset/chilly-bananas-train.md new file mode 100644 index 0000000000..b0305f9e61 --- /dev/null +++ b/.changeset/chilly-bananas-train.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: double event processing in firefox due to event object being garbage collected diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index fa3bf0b021..19bd1cfa18 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -141,6 +141,13 @@ export function delegate(events) { } } +// used to store the reference to the currently propagated event +// to prevent garbage collection between microtasks in Firefox +// If the event object is GCed too early, the expando __root property +// set on the event object is lost, causing the event delegation +// to process the event twice +let last_propagated_event = null; + /** * @this {EventTarget} * @param {Event} event @@ -153,6 +160,8 @@ export function handle_event_propagation(event) { var path = event.composedPath?.() || []; var current_target = /** @type {null | Element} */ (path[0] || event.target); + last_propagated_event = event; + // composedPath contains list of nodes the event has propagated through. // We check __root to skip all nodes below it in case this is a // parent of the __root node, which indicates that there's nested