From d8d9b390e3853098c4693cf63d447378fa2a23fc Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 5 Mar 2026 14:45:59 -0500 Subject: [PATCH 1/3] fix(engine-core): dedupe additions to `WeakMultimap` Also remove legacy compat code --- .../src/framework/weak-multimap.ts | 51 ++++--------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/packages/@lwc/engine-core/src/framework/weak-multimap.ts b/packages/@lwc/engine-core/src/framework/weak-multimap.ts index 0044be5921..09e0c08b6b 100644 --- a/packages/@lwc/engine-core/src/framework/weak-multimap.ts +++ b/packages/@lwc/engine-core/src/framework/weak-multimap.ts @@ -7,50 +7,17 @@ import { ArrayPush, ArraySplice, isUndefined } from '@lwc/shared'; -const supportsWeakRefs = - typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function'; - /** * A map where the keys are weakly held and the values are a Set that are also each weakly held. * The goal is to avoid leaking the values, which is what would happen with a WeakMap>. * * Note that this is currently only intended to be used in dev/PRODDEBUG environments. * It leaks in legacy browsers, which may be undesired. + * + * This implementation relies on the WeakRef/FinalizationRegistry proposal. + * For some background, see: https://github.com/tc39/proposal-weakrefs */ -export interface WeakMultiMap { - get(key: T): ReadonlySet; - add(key: T, vm: V): void; - delete(key: T): void; -} - -// In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't -class LegacyWeakMultiMap implements WeakMultiMap { - private _map: WeakMap> = new WeakMap(); - - private _getValues(key: K): Set { - let values = this._map.get(key); - if (isUndefined(values)) { - values = new Set(); - this._map.set(key, values); - } - return values; - } - - get(key: K): ReadonlySet { - return this._getValues(key); - } - add(key: K, vm: V) { - const set = this._getValues(key); - set.add(vm); - } - delete(key: K) { - this._map.delete(key); - } -} - -// This implementation relies on the WeakRef/FinalizationRegistry proposal. -// For some background, see: https://github.com/tc39/proposal-weakrefs -class ModernWeakMultiMap implements WeakMultiMap { +export class WeakMultimap { private _map = new WeakMap[]>(); private _registry = new FinalizationRegistry((weakRefs: WeakRef[]) => { @@ -88,8 +55,12 @@ class ModernWeakMultiMap implements WeakMult } add(key: K, value: V) { const weakRefs = this._getWeakRefs(key); - // We could check for duplicate values here, but it doesn't seem worth it. - // We transform the output into a Set anyway + // Skip adding if already present + for (const weakRef of weakRefs) { + if (weakRef.deref() === value) { + return; + } + } ArrayPush.call(weakRefs, new WeakRef(value)); // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry @@ -105,5 +76,3 @@ class ModernWeakMultiMap implements WeakMult this._map.delete(key); } } - -export const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap; From 0ebb81686dd4ff7368bff0b4562f2f6057e3949d Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 5 Mar 2026 15:54:37 -0500 Subject: [PATCH 2/3] chore: update link and fix case --- packages/@lwc/engine-core/src/framework/weak-multimap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@lwc/engine-core/src/framework/weak-multimap.ts b/packages/@lwc/engine-core/src/framework/weak-multimap.ts index 09e0c08b6b..087bb323f2 100644 --- a/packages/@lwc/engine-core/src/framework/weak-multimap.ts +++ b/packages/@lwc/engine-core/src/framework/weak-multimap.ts @@ -15,9 +15,9 @@ import { ArrayPush, ArraySplice, isUndefined } from '@lwc/shared'; * It leaks in legacy browsers, which may be undesired. * * This implementation relies on the WeakRef/FinalizationRegistry proposal. - * For some background, see: https://github.com/tc39/proposal-weakrefs + * For some background, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef */ -export class WeakMultimap { +export class WeakMultiMap { private _map = new WeakMap[]>(); private _registry = new FinalizationRegistry((weakRefs: WeakRef[]) => { From fed24dcc096dbf594ec39f3a521bacbc94bcd148 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 5 Mar 2026 16:00:38 -0500 Subject: [PATCH 3/3] chore: remove legacy note --- packages/@lwc/engine-core/src/framework/weak-multimap.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@lwc/engine-core/src/framework/weak-multimap.ts b/packages/@lwc/engine-core/src/framework/weak-multimap.ts index 087bb323f2..947565dfda 100644 --- a/packages/@lwc/engine-core/src/framework/weak-multimap.ts +++ b/packages/@lwc/engine-core/src/framework/weak-multimap.ts @@ -12,9 +12,8 @@ import { ArrayPush, ArraySplice, isUndefined } from '@lwc/shared'; * The goal is to avoid leaking the values, which is what would happen with a WeakMap>. * * Note that this is currently only intended to be used in dev/PRODDEBUG environments. - * It leaks in legacy browsers, which may be undesired. * - * This implementation relies on the WeakRef/FinalizationRegistry proposal. + * This implementation relies on WeakRefs and FinalizationRegistry. * For some background, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef */ export class WeakMultiMap {