@samitouri / QOS-React / commits / 67a05d03e3

fix[devtools]: fixed duplicated backend activation with multiple renderers (#26807)

## Summary Initially reported in https://github.com/facebook/react/issues/26797. Was not able to reproduce the exact same problem, but found this case: 1. Open corresponding codepen from the issue in debug mode 2. Open components tab of the extension 3. Refresh the page Received multiple errors: - Warning in the Console tab: Invalid renderer id "2". - Error in the Components tab: Uncaught Error: Cannot add node "3" because a node with that id is already in the Store. This problem has occurred after landing a fix in https://github.com/facebook/react/pull/26779. Looks like Chrome is keeping the injected scripts (the backend in this case) and we start backend twice.

Ruslan Lesiutin committed May 12, 2023 at 14:59 UTC 67a05d03e38b9837e27c9fe0a673557e63ff03c5
2 files changed +14 -4
packages/react-devtools-extensions/src/backend.js
+1
@@ -29,5 +29,6 @@ function setup(hook: ?DevToolsHook) {
29 initBackend,
30 setupNativeStyleEditor,
31 });
32 +
33 hook.emit('devtools-backend-installed', COMPACT_VERSION_NAME);
34 }
packages/react-devtools-extensions/src/backendManager.js
+13 -4
@@ -58,7 +58,7 @@ function setup(hook: ?DevToolsHook) {
58
59 // register renderers that have already injected themselves.
60 hook.renderers.forEach(renderer => {
61 - registerRenderer(renderer);
61 + registerRenderer(renderer, hook);
62 });
63
64 // Activate and remove from required all present backends, registered within the hook
@@ -71,7 +71,7 @@ function setup(hook: ?DevToolsHook) {
71
72 // register renderers that inject themselves later.
73 hook.sub('renderer', ({renderer}) => {
74 - registerRenderer(renderer);
74 + registerRenderer(renderer, hook);
75 updateRequiredBackends();
76 });
77
@@ -84,12 +84,16 @@ function setup(hook: ?DevToolsHook) {
84
85 const requiredBackends = new Set<string>();
86
87 -function registerRenderer(renderer: ReactRenderer) {
87 +function registerRenderer(renderer: ReactRenderer, hook: DevToolsHook) {
88 let version = renderer.reconcilerVersion || renderer.version;
89 if (!hasAssignedBackend(version)) {
90 version = COMPACT_VERSION_NAME;
91 }
92 - requiredBackends.add(version);
92 +
93 + // Check if required backend is already activated, no need to require again
94 + if (!hook.backends.has(version)) {
95 + requiredBackends.add(version);
96 + }
97 }
98
99 function activateBackend(version: string, hook: DevToolsHook) {
@@ -97,6 +101,7 @@ function activateBackend(version: string, hook: DevToolsHook) {
101 if (!backend) {
102 throw new Error(`Could not find backend for version "${version}"`);
103 }
104 +
105 const {Agent, Bridge, initBackend, setupNativeStyleEditor} = backend;
106 const bridge = new Bridge({
107 listen(fn) {
@@ -157,6 +162,10 @@ function activateBackend(version: string, hook: DevToolsHook) {
162
163 // tell the service worker which versions of backends are needed for the current page
164 function updateRequiredBackends() {
165 + if (requiredBackends.size === 0) {
166 + return;
167 + }
168 +
169 window.postMessage(
170 {
171 source: 'react-devtools-backend-manager',