From 475f0a2bed5264681e2cc7823688b1ee2ba33cee Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 28 Sep 2026 07:00:18 +0000 Subject: [PATCH] fix(core, web): skip hot-restart listener cleanup in profile mode Profile builds left dart.vm.product unset, so web listeners were stored under the shared 'no-op' key and the next subscription cancelled them. --- .../lib/src/interop/utils/utils.dart | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/firebase_core/firebase_core_web/lib/src/interop/utils/utils.dart b/packages/firebase_core/firebase_core_web/lib/src/interop/utils/utils.dart index 0b7232b628f9..cf62d83805a2 100644 --- a/packages/firebase_core/firebase_core_web/lib/src/interop/utils/utils.dart +++ b/packages/firebase_core/firebase_core_web/lib/src/interop/utils/utils.dart @@ -14,8 +14,19 @@ import 'package:web/web.dart' as web; import 'func.dart'; +// Hot restart exists only in debug mode. This must match Flutter's +// kDebugMode (`!dart.vm.product && !dart.vm.profile`). Profile builds leave +// dart.vm.product false, so gating on product mode alone still stores JS +// unsubscribe functions on window. Plugins then share the key 'no-op' +// outside debug and cancel the previous listener on the next subscription. +// See https://github.com/firebase/flutterfire/issues/18728. // ignore: do_not_use_environment -const bool _kDebugMode = !bool.fromEnvironment('dart.vm.product'); +const bool _kReleaseMode = bool.fromEnvironment('dart.vm.product'); + +// ignore: do_not_use_environment +const bool _kProfileMode = bool.fromEnvironment('dart.vm.profile'); + +const bool _kDebugMode = !_kReleaseMode && !_kProfileMode; /// Handles the [Future] object with the provided [mapper] function. JSPromise handleFutureWithMapper(