react-native
Version:
A framework for building native apps using React
178 lines (157 loc) • 5.92 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
;
import type {Domain} from '../../src/private/devsupport/rndevtools/setUpFuseboxReactDevToolsDispatcher';
import type {Spec as NativeReactDevToolsRuntimeSettingsModuleSpec} from '../../src/private/devsupport/rndevtools/specs/NativeReactDevToolsRuntimeSettingsModule';
if (__DEV__) {
if (typeof global.queueMicrotask !== 'function') {
console.error(
'queueMicrotask should exist before setting up React DevTools.',
);
}
// Keep in sync with ExceptionsManager/installConsoleErrorReporter
// $FlowExpectedError[prop-missing]
if (console._errorOriginal != null) {
console.error(
'ExceptionsManager should be set up after React DevTools to avoid console.error arguments mutation',
);
}
}
if (__DEV__) {
// Register dispatcher on global, which can be used later by Chrome DevTools frontend
require('../../src/private/devsupport/rndevtools/setUpFuseboxReactDevToolsDispatcher');
const {
initialize,
connectWithCustomMessagingProtocol,
} = require('react-devtools-core');
const reactDevToolsSettingsManager = require('../../src/private/devsupport/rndevtools/ReactDevToolsSettingsManager');
const serializedHookSettings =
reactDevToolsSettingsManager.getGlobalHookSettings();
const maybeReactDevToolsRuntimeSettingsModuleModule =
require('../../src/private/devsupport/rndevtools/specs/NativeReactDevToolsRuntimeSettingsModule').default;
let hookSettings = null;
if (serializedHookSettings != null) {
try {
const parsedSettings = JSON.parse(serializedHookSettings);
hookSettings = parsedSettings;
} catch {
console.error(
'Failed to parse persisted React DevTools hook settings. React DevTools will be initialized with default settings.',
);
}
}
const {
isProfiling: shouldStartProfilingNow,
profilingSettings: initialProfilingSettings,
} = readReloadAndProfileConfig(maybeReactDevToolsRuntimeSettingsModuleModule);
// Install hook before React is loaded.
initialize(hookSettings, shouldStartProfilingNow, initialProfilingSettings);
// This should be defined in DEV, otherwise error is expected.
const fuseboxReactDevToolsDispatcher =
global.__FUSEBOX_REACT_DEVTOOLS_DISPATCHER__;
const reactDevToolsFuseboxGlobalBindingName =
fuseboxReactDevToolsDispatcher.BINDING_NAME;
const ReactNativeStyleAttributes =
require('../Components/View/ReactNativeStyleAttributes').default;
const resolveRNStyle = require('../StyleSheet/flattenStyle').default;
function handleReactDevToolsSettingsUpdate(settings: Object) {
reactDevToolsSettingsManager.setGlobalHookSettings(
JSON.stringify(settings),
);
}
let disconnect = null;
function disconnectBackendFromReactDevToolsInFuseboxIfNeeded() {
if (disconnect != null) {
disconnect();
disconnect = null;
}
}
function connectToReactDevToolsInFusebox(domain: Domain) {
const {
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
} = readReloadAndProfileConfig(
maybeReactDevToolsRuntimeSettingsModuleModule,
);
disconnect = connectWithCustomMessagingProtocol({
onSubscribe: listener => {
domain.onMessage.addEventListener(listener);
},
onUnsubscribe: listener => {
domain.onMessage.removeEventListener(listener);
},
onMessage: (event, payload) => {
domain.sendMessage({event, payload});
},
nativeStyleEditorValidAttributes: Object.keys(ReactNativeStyleAttributes),
resolveRNStyle,
onSettingsUpdated: handleReactDevToolsSettingsUpdate,
isReloadAndProfileSupported,
isProfiling,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
});
}
// 1. If React DevTools has already been opened and initialized in Fusebox, bindings survive reloads
if (global[reactDevToolsFuseboxGlobalBindingName] != null) {
disconnectBackendFromReactDevToolsInFuseboxIfNeeded();
const domain =
fuseboxReactDevToolsDispatcher.initializeDomain('react-devtools');
connectToReactDevToolsInFusebox(domain);
}
// 2. If React DevTools panel in Fusebox was opened for the first time after the runtime has been created
// 2. OR if React DevTools frontend was re-initialized: Chrome DevTools was closed and then re-opened
global.__FUSEBOX_REACT_DEVTOOLS_DISPATCHER__.onDomainInitialization.addEventListener(
(domain: Domain) => {
if (domain.name === 'react-devtools') {
disconnectBackendFromReactDevToolsInFuseboxIfNeeded();
connectToReactDevToolsInFusebox(domain);
}
},
);
}
function readReloadAndProfileConfig(
maybeModule: ?NativeReactDevToolsRuntimeSettingsModuleSpec,
) {
const isReloadAndProfileSupported = maybeModule != null;
const config = maybeModule?.getReloadAndProfileConfig();
const isProfiling = config?.shouldReloadAndProfile === true;
const profilingSettings = {
recordChangeDescriptions: config?.recordChangeDescriptions === true,
recordTimeline: false,
};
const onReloadAndProfile = (recordChangeDescriptions: boolean) => {
if (maybeModule == null) {
return;
}
maybeModule.setReloadAndProfileConfig({
shouldReloadAndProfile: true,
recordChangeDescriptions,
});
};
const onReloadAndProfileFlagsReset = () => {
if (maybeModule == null) {
return;
}
maybeModule.setReloadAndProfileConfig({
shouldReloadAndProfile: false,
recordChangeDescriptions: false,
});
};
return {
isReloadAndProfileSupported,
isProfiling,
profilingSettings,
onReloadAndProfile,
onReloadAndProfileFlagsReset,
};
}