Files
react/packages/react-devtools-inline/src/backend.js
Ruslan Lesiutin bfe91fbecf refactor[react-devtools]: flatten reload and profile config (#31132)
Stacked on https://github.com/facebook/react/pull/31131. See last
commit.

This is a clean-up and a pre-requisite for next changes:
1. `ReloadAndProfileConfig` is now split into boolean value and settings
object. This is mainly because I will add one more setting soon, and
also because settings might be persisted for a longer time than the flag
which signals if the Backend was reloaded for profiling. Ideally, this
settings should probably be moved to the global Hook object, same as we
did for console patching.
2. Host is now responsible for reseting the cached values, Backend will
execute provided `onReloadAndProfileFlagsReset` callback.
2024-10-09 13:57:02 +01:00

135 lines
4.5 KiB
JavaScript

/** @flow */
import Agent from 'react-devtools-shared/src/backend/agent';
import Bridge from 'react-devtools-shared/src/bridge';
import {initBackend} from 'react-devtools-shared/src/backend';
import {installHook} from 'react-devtools-shared/src/hook';
import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
import type {Wall} from 'react-devtools-shared/src/frontend/types';
import {
getIfReloadedAndProfiling,
getIsReloadAndProfileSupported,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
} from 'react-devtools-shared/src/utils';
function startActivation(contentWindow: any, bridge: BackendBridge) {
const onSavedPreferences = (data: $FlowFixMe) => {
// This is the only message we're listening for,
// so it's safe to cleanup after we've received it.
bridge.removeListener('savedPreferences', onSavedPreferences);
const {
appendComponentStack,
breakOnConsoleErrors,
componentFilters,
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
} = data;
contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ =
appendComponentStack;
contentWindow.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ =
breakOnConsoleErrors;
contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
contentWindow.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ =
showInlineWarningsAndErrors;
contentWindow.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
hideConsoleLogsInStrictMode;
// TRICKY
// The backend entry point may be required in the context of an iframe or the parent window.
// If it's required within the parent window, store the saved values on it as well,
// since the injected renderer interface will read from window.
// Technically we don't need to store them on the contentWindow in this case,
// but it doesn't really hurt anything to store them there too.
if (contentWindow !== window) {
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack;
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = breakOnConsoleErrors;
window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ =
showInlineWarningsAndErrors;
window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
hideConsoleLogsInStrictMode;
}
finishActivation(contentWindow, bridge);
};
bridge.addListener('savedPreferences', onSavedPreferences);
// The backend may be unable to read saved preferences directly,
// because they are stored in localStorage within the context of the extension (on the frontend).
// Instead it relies on the extension to pass preferences through.
// Because we might be in a sandboxed iframe, we have to ask for them by way of postMessage().
bridge.send('getSavedPreferences');
}
function finishActivation(contentWindow: any, bridge: BackendBridge) {
const agent = new Agent(
bridge,
getIfReloadedAndProfiling(),
onReloadAndProfile,
);
onReloadAndProfileFlagsReset();
const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook) {
initBackend(hook, agent, contentWindow, getIsReloadAndProfileSupported());
// Setup React Native style editor if a renderer like react-native-web has injected it.
if (hook.resolveRNStyle) {
setupNativeStyleEditor(
bridge,
agent,
hook.resolveRNStyle,
hook.nativeStyleEditorValidAttributes,
);
}
}
}
export function activate(
contentWindow: any,
{
bridge,
}: {
bridge?: BackendBridge,
} = {},
): void {
if (bridge == null) {
bridge = createBridge(contentWindow);
}
startActivation(contentWindow, bridge);
}
export function createBridge(contentWindow: any, wall?: Wall): BackendBridge {
const {parent} = contentWindow;
if (wall == null) {
wall = {
listen(fn) {
const onMessage = ({data}: $FlowFixMe) => {
fn(data);
};
contentWindow.addEventListener('message', onMessage);
return () => {
contentWindow.removeEventListener('message', onMessage);
};
},
send(event: string, payload: any, transferable?: Array<any>) {
parent.postMessage({event, payload}, '*', transferable);
},
};
}
return (new Bridge(wall): BackendBridge);
}
export function initialize(contentWindow: any): void {
installHook(contentWindow);
}