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.
This commit is contained in:
Ruslan Lesiutin
2023-05-12 14:59:53 +01:00
committed by GitHub
parent df12d7eac4
commit 67a05d03e3
2 changed files with 14 additions and 4 deletions
+1
View File
@@ -29,5 +29,6 @@ function setup(hook: ?DevToolsHook) {
initBackend,
setupNativeStyleEditor,
});
hook.emit('devtools-backend-installed', COMPACT_VERSION_NAME);
}
+13 -4
View File
@@ -58,7 +58,7 @@ function setup(hook: ?DevToolsHook) {
// register renderers that have already injected themselves.
hook.renderers.forEach(renderer => {
registerRenderer(renderer);
registerRenderer(renderer, hook);
});
// Activate and remove from required all present backends, registered within the hook
@@ -71,7 +71,7 @@ function setup(hook: ?DevToolsHook) {
// register renderers that inject themselves later.
hook.sub('renderer', ({renderer}) => {
registerRenderer(renderer);
registerRenderer(renderer, hook);
updateRequiredBackends();
});
@@ -84,12 +84,16 @@ function setup(hook: ?DevToolsHook) {
const requiredBackends = new Set<string>();
function registerRenderer(renderer: ReactRenderer) {
function registerRenderer(renderer: ReactRenderer, hook: DevToolsHook) {
let version = renderer.reconcilerVersion || renderer.version;
if (!hasAssignedBackend(version)) {
version = COMPACT_VERSION_NAME;
}
requiredBackends.add(version);
// Check if required backend is already activated, no need to require again
if (!hook.backends.has(version)) {
requiredBackends.add(version);
}
}
function activateBackend(version: string, hook: DevToolsHook) {
@@ -97,6 +101,7 @@ function activateBackend(version: string, hook: DevToolsHook) {
if (!backend) {
throw new Error(`Could not find backend for version "${version}"`);
}
const {Agent, Bridge, initBackend, setupNativeStyleEditor} = backend;
const bridge = new Bridge({
listen(fn) {
@@ -157,6 +162,10 @@ function activateBackend(version: string, hook: DevToolsHook) {
// tell the service worker which versions of backends are needed for the current page
function updateRequiredBackends() {
if (requiredBackends.size === 0) {
return;
}
window.postMessage(
{
source: 'react-devtools-backend-manager',