From b8132fc382eb26edfbd55b2449cd6379a5aabc6a Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 5 Sep 2024 15:55:48 -0400 Subject: [PATCH] fix[react-devtools]: initialize bridge only after domain is ready --- .../react_devtools/ReactDevToolsModel.ts | 26 +++++++++++-------- .../react_devtools/ReactDevToolsViewBase.ts | 16 +++++++----- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/front_end/panels/react_devtools/ReactDevToolsModel.ts b/front_end/panels/react_devtools/ReactDevToolsModel.ts index 73ae2a5c320..ca9b7725a09 100644 --- a/front_end/panels/react_devtools/ReactDevToolsModel.ts +++ b/front_end/panels/react_devtools/ReactDevToolsModel.ts @@ -36,8 +36,8 @@ export class ReactDevToolsModel extends SDK.SDKModel.SDKModel { readonly #listeners: Set = new Set(); #initializeCalled: boolean = false; #initialized: boolean = false; - #bridge: ReactDevToolsTypes.Bridge | null; - #store: ReactDevToolsTypes.Store | null; + #bridge: ReactDevToolsTypes.Bridge | null = null; + #store: ReactDevToolsTypes.Store | null = null; constructor(target: SDK.Target.Target) { super(target); @@ -52,8 +52,6 @@ export class ReactDevToolsModel extends SDK.SDKModel.SDKModel { }, send: (event, payload): void => void this.#sendMessage({event, payload}), }; - this.#bridge = ReactDevTools.createBridge(this.#wall); - this.#store = ReactDevTools.createStore(this.#bridge); const bindingsModel = target.model(ReactNativeModels.ReactDevToolsBindingsModel.ReactDevToolsBindingsModel); if (bindingsModel == null) { @@ -82,13 +80,16 @@ export class ReactDevToolsModel extends SDK.SDKModel.SDKModel { window.addEventListener('beforeunload', () => this.#bridge?.shutdown()); } - async ensureInitialized(): Promise { + ensureInitialized(): void { if (this.#initializeCalled) { return; } this.#initializeCalled = true; + void this.#initialize(); + } + async #initialize(): Promise { try { const bindingsModel = this.#bindingsModel; await bindingsModel.enable(); @@ -101,7 +102,7 @@ export class ReactDevToolsModel extends SDK.SDKModel.SDKModel { await bindingsModel.initializeDomain(ReactDevToolsModel.FUSEBOX_BINDING_NAMESPACE); this.#initialized = true; - this.dispatchEventToListeners(Events.InitializationCompleted); + this.#finishInitializationAndNotify(); } catch (e) { this.dispatchEventToListeners(Events.InitializationFailed, e.message); } @@ -152,17 +153,20 @@ export class ReactDevToolsModel extends SDK.SDKModel.SDKModel { throw new Error('ReactDevToolsModel failed to handle BackendExecutionContextCreated event: ReactDevToolsBindingsModel was null'); } - this.#bridge = ReactDevTools.createBridge(this.#wall); - this.#store = ReactDevTools.createStore(this.#bridge); - // This could happen if the app was reloaded while ReactDevToolsBindingsModel was initializing if (!rdtBindingsModel.isEnabled()) { - void this.ensureInitialized(); + this.ensureInitialized(); } else { - this.dispatchEventToListeners(Events.InitializationCompleted); + this.#finishInitializationAndNotify(); } } + #finishInitializationAndNotify(): void { + this.#bridge = ReactDevTools.createBridge(this.#wall); + this.#store = ReactDevTools.createStore(this.#bridge); + this.dispatchEventToListeners(Events.InitializationCompleted); + } + #handleBackendExecutionContextUnavailable({data: errorMessage}: ReactDevToolsBindingsBackendExecutionContextUnavailableEvent): void { this.dispatchEventToListeners(Events.InitializationFailed, errorMessage); } diff --git a/front_end/panels/react_devtools/ReactDevToolsViewBase.ts b/front_end/panels/react_devtools/ReactDevToolsViewBase.ts index 8b41ba3fac8..5de203927e8 100644 --- a/front_end/panels/react_devtools/ReactDevToolsViewBase.ts +++ b/front_end/panels/react_devtools/ReactDevToolsViewBase.ts @@ -96,12 +96,6 @@ export class ReactDevToolsViewBase extends UI.View.SimpleView implements modelAdded(model: ReactDevToolsModel): void { this.#model = model; - if (model.isInitialized()) { - // Already initialized from another rendered React DevTools view - render - // from initialized state - this.#renderDevToolsView(); - } - model.addEventListener( ReactDevToolsModelEvents.InitializationCompleted, this.#handleInitializationCompleted, @@ -117,7 +111,15 @@ export class ReactDevToolsViewBase extends UI.View.SimpleView implements this.#handleBackendDestroyed, this, ); - void model.ensureInitialized(); + + if (model.isInitialized()) { + // Already initialized from another rendered React DevTools panel - render + // from initialized state + this.#renderDevToolsView(); + } else { + // Once initialized, it will emit InitializationCompleted event + model.ensureInitialized(); + } } modelRemoved(model: ReactDevToolsModel): void {