Skip to content

Commit

Permalink
Add: reload to profile for Fusebox (#31021)
Browse files Browse the repository at this point in the history
## Summary

Add reload to profile for Fusebox 

Stacked on #31048. See
6be1977

## How did you test this change?

Test E2E in [D63233256](https://www.internalfb.com/diff/D63233256)
  • Loading branch information
EdmondChuiHW authored Sep 26, 2024
1 parent b091ef7 commit 204a551
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 42 deletions.
13 changes: 10 additions & 3 deletions packages/react-devtools-core/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import type {
import type {
DevToolsHook,
DevToolsHookSettings,
ReloadAndProfileConfig,
ReloadAndProfileConfigPersistence,
} from 'react-devtools-shared/src/backend/types';
import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';

Expand All @@ -40,6 +42,7 @@ type ConnectOptions = {
websocket?: ?WebSocket,
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
isReloadAndProfileSupported?: boolean,
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence,
};

let savedComponentFilters: Array<ComponentFilter> =
Expand All @@ -60,8 +63,9 @@ export function initialize(
maybeSettingsOrSettingsPromise?:
| DevToolsHookSettings
| Promise<DevToolsHookSettings>,
reloadAndProfileConfig?: ReloadAndProfileConfig,
) {
installHook(window, maybeSettingsOrSettingsPromise);
installHook(window, maybeSettingsOrSettingsPromise, reloadAndProfileConfig);
}

export function connectToDevTools(options: ?ConnectOptions) {
Expand All @@ -82,6 +86,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
isAppActive = () => true,
onSettingsUpdated,
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
reloadAndProfileConfigPersistence,
} = options || {};

const protocol = useHttps ? 'wss' : 'ws';
Expand Down Expand Up @@ -175,7 +180,7 @@ export function connectToDevTools(options: ?ConnectOptions) {

// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
// $FlowFixMe[incompatible-call] found when upgrading Flow
const agent = new Agent(bridge);
const agent = new Agent(bridge, reloadAndProfileConfigPersistence);
if (onSettingsUpdated != null) {
agent.addListener('updateHookSettings', onSettingsUpdated);
}
Expand Down Expand Up @@ -315,6 +320,7 @@ type ConnectWithCustomMessagingOptions = {
resolveRNStyle?: ResolveNativeStyle,
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
isReloadAndProfileSupported?: boolean,
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence,
};

export function connectWithCustomMessagingProtocol({
Expand All @@ -325,6 +331,7 @@ export function connectWithCustomMessagingProtocol({
resolveRNStyle,
onSettingsUpdated,
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
reloadAndProfileConfigPersistence,
}: ConnectWithCustomMessagingOptions): Function {
const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook == null) {
Expand Down Expand Up @@ -361,7 +368,7 @@ export function connectWithCustomMessagingProtocol({
bridge.send('overrideComponentFilters', savedComponentFilters);
}

const agent = new Agent(bridge);
const agent = new Agent(bridge, reloadAndProfileConfigPersistence);
if (onSettingsUpdated != null) {
agent.addListener('updateHookSettings', onSettingsUpdated);
}
Expand Down
5 changes: 4 additions & 1 deletion packages/react-devtools-fusebox/src/frontend.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ export type Bridge = {
};
export type Store = Object;
export type BrowserTheme = 'dark' | 'light';
export type Config = {
supportsReloadAndProfile?: boolean,
};

export function createBridge(wall: Wall): Bridge;
export function createStore(bridge: Bridge): Store;
export function createStore(bridge: Bridge, config?: Config): Store;

export type Source = {
sourceURL: string,
Expand Down
10 changes: 9 additions & 1 deletion packages/react-devtools-shared/src/attachRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
DevToolsHook,
RendererID,
} from 'react-devtools-shared/src/backend/types';
import type {ReloadAndProfileConfig} from './backend/types';

import {attach as attachFlight} from 'react-devtools-shared/src/backend/flight/renderer';
import {attach as attachFiber} from 'react-devtools-shared/src/backend/fiber/renderer';
Expand All @@ -29,6 +30,7 @@ export default function attachRenderer(
id: RendererID,
renderer: ReactRenderer,
global: Object,
reloadAndProfileConfig: ReloadAndProfileConfig,
): RendererInterface | void {
// only attach if the renderer is compatible with the current version of the backend
if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) {
Expand All @@ -48,7 +50,13 @@ export default function attachRenderer(
renderer.currentDispatcherRef != null
) {
// react-reconciler v16+
rendererInterface = attachFiber(hook, id, renderer, global);
rendererInterface = attachFiber(
hook,
id,
renderer,
global,
reloadAndProfileConfig,
);
} else if (renderer.ComponentTree) {
// react-dom v15
rendererInterface = attachLegacy(hook, id, renderer, global);
Expand Down
52 changes: 27 additions & 25 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,7 @@
*/

import EventEmitter from '../events';
import {
SESSION_STORAGE_LAST_SELECTION_KEY,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
__DEBUG__,
} from '../constants';
import {
sessionStorageGetItem,
sessionStorageRemoveItem,
sessionStorageSetItem,
} from 'react-devtools-shared/src/storage';
import {SESSION_STORAGE_LAST_SELECTION_KEY, __DEBUG__} from '../constants';
import setupHighlighter from './views/Highlighter';
import {
initialize as setupTraceUpdates,
Expand All @@ -36,9 +26,16 @@ import type {
RendererID,
RendererInterface,
DevToolsHookSettings,
ReloadAndProfileConfigPersistence,
} from './types';
import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
import {isReactNativeEnvironment} from './utils';
import {defaultReloadAndProfileConfigPersistence} from '../utils';
import {
sessionStorageGetItem,
sessionStorageRemoveItem,
sessionStorageSetItem,
} from '../storage';

const debug = (methodName: string, ...args: Array<string>) => {
if (__DEBUG__) {
Expand Down Expand Up @@ -159,21 +156,27 @@ export default class Agent extends EventEmitter<{
_persistedSelection: PersistedSelection | null = null;
_persistedSelectionMatch: PathMatch | null = null;
_traceUpdatesEnabled: boolean = false;
_reloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence;

constructor(bridge: BackendBridge) {
constructor(
bridge: BackendBridge,
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence = defaultReloadAndProfileConfigPersistence,
) {
super();

if (
sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true'
) {
this._reloadAndProfileConfigPersistence = reloadAndProfileConfigPersistence;
const {getReloadAndProfileConfig, setReloadAndProfileConfig} =
reloadAndProfileConfigPersistence;
const reloadAndProfileConfig = getReloadAndProfileConfig();
if (reloadAndProfileConfig.shouldReloadAndProfile) {
this._recordChangeDescriptions =
sessionStorageGetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
) === 'true';
reloadAndProfileConfig.recordChangeDescriptions;
this._isProfiling = true;

sessionStorageRemoveItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY);
sessionStorageRemoveItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY);
setReloadAndProfileConfig({
shouldReloadAndProfile: false,
recordChangeDescriptions: false,
});
}

const persistedSelectionString = sessionStorageGetItem(
Expand Down Expand Up @@ -671,11 +674,10 @@ export default class Agent extends EventEmitter<{

reloadAndProfile: (recordChangeDescriptions: boolean) => void =
recordChangeDescriptions => {
sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
sessionStorageSetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
recordChangeDescriptions ? 'true' : 'false',
);
this._reloadAndProfileConfigPersistence.setReloadAndProfileConfig({
shouldReloadAndProfile: true,
recordChangeDescriptions,
});

// This code path should only be hit if the shell has explicitly told the Store that it supports profiling.
// In that case, the shell must also listen for this specific message to know when it needs to reload the app.
Expand Down
16 changes: 6 additions & 10 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
utfEncodeString,
filterOutLocationComponentFilters,
} from 'react-devtools-shared/src/utils';
import {sessionStorageGetItem} from 'react-devtools-shared/src/storage';
import {
formatConsoleArgumentsToSingleString,
gt,
Expand All @@ -61,8 +60,6 @@ import {
__DEBUG__,
PROFILING_FLAG_BASIC_SUPPORT,
PROFILING_FLAG_TIMELINE_SUPPORT,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
TREE_OPERATION_ADD,
TREE_OPERATION_REMOVE,
TREE_OPERATION_REORDER_CHILDREN,
Expand Down Expand Up @@ -106,6 +103,7 @@ import {
supportsOwnerStacks,
supportsConsoleTasks,
} from './DevToolsFiberComponentStack';
import type {ReloadAndProfileConfig} from '../types';

// $FlowFixMe[method-unbinding]
const toString = Object.prototype.toString;
Expand Down Expand Up @@ -865,6 +863,7 @@ export function attach(
rendererID: number,
renderer: ReactRenderer,
global: Object,
reloadAndProfileConfig: ReloadAndProfileConfig,
): RendererInterface {
// Newer versions of the reconciler package also specific reconciler version.
// If that version number is present, use it.
Expand Down Expand Up @@ -5213,13 +5212,10 @@ export function attach(
}

// Automatically start profiling so that we don't miss timing info from initial "mount".
if (
sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true'
) {
startProfiling(
sessionStorageGetItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY) ===
'true',
);
if (reloadAndProfileConfig.shouldReloadAndProfile) {
const shouldRecordChangeDescriptions =
reloadAndProfileConfig.recordChangeDescriptions;
startProfiling(shouldRecordChangeDescriptions);
}

function getNearestFiber(devtoolsInstance: DevToolsInstance): null | Fiber {
Expand Down
14 changes: 14 additions & 0 deletions packages/react-devtools-shared/src/backend/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,20 @@ export type DevToolsBackend = {
setupNativeStyleEditor?: SetupNativeStyleEditor,
};

export type ReloadAndProfileConfig = {
shouldReloadAndProfile: boolean,
recordChangeDescriptions: boolean,
};

// Linter doesn't speak Flow's `Partial` type
// eslint-disable-next-line no-undef
type PartialReloadAndProfileConfig = Partial<ReloadAndProfileConfig>;

export type ReloadAndProfileConfigPersistence = {
setReloadAndProfileConfig: (config: PartialReloadAndProfileConfig) => void,
getReloadAndProfileConfig: () => ReloadAndProfileConfig,
};

export type DevToolsHook = {
listeners: {[key: string]: Array<Handler>, ...},
rendererInterfaces: Map<RendererID, RendererInterface>,
Expand Down
11 changes: 10 additions & 1 deletion packages/react-devtools-shared/src/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
RendererInterface,
DevToolsBackend,
DevToolsHookSettings,
ReloadAndProfileConfig,
} from './backend/types';

import {
Expand All @@ -26,6 +27,7 @@ import {
import attachRenderer from './attachRenderer';
import formatConsoleArguments from 'react-devtools-shared/src/backend/utils/formatConsoleArguments';
import formatWithStyles from 'react-devtools-shared/src/backend/utils/formatWithStyles';
import {defaultReloadAndProfileConfigPersistence} from './utils';

// React's custom built component stack strings match "\s{4}in"
// Chrome's prefix matches "\s{4}at"
Expand Down Expand Up @@ -54,6 +56,7 @@ export function installHook(
maybeSettingsOrSettingsPromise?:
| DevToolsHookSettings
| Promise<DevToolsHookSettings>,
reloadAndProfileConfig?: ReloadAndProfileConfig = defaultReloadAndProfileConfigPersistence.getReloadAndProfileConfig(),
): DevToolsHook | null {
if (target.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
return null;
Expand Down Expand Up @@ -207,7 +210,13 @@ export function installHook(
reactBuildType,
});

const rendererInterface = attachRenderer(hook, id, renderer, target);
const rendererInterface = attachRenderer(
hook,
id,
renderer,
target,
reloadAndProfileConfig,
);
if (rendererInterface != null) {
hook.rendererInterfaces.set(id, rendererInterface);
hook.emit('renderer-attached', {id, rendererInterface});
Expand Down
45 changes: 44 additions & 1 deletion packages/react-devtools-shared/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
TREE_OPERATION_UPDATE_TREE_BASE_DURATION,
LOCAL_STORAGE_COMPONENT_FILTER_PREFERENCES_KEY,
LOCAL_STORAGE_OPEN_IN_EDITOR_URL,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
} from './constants';
import {
ComponentFilterElementType,
Expand All @@ -50,7 +52,12 @@ import {
ElementTypeMemo,
ElementTypeVirtual,
} from 'react-devtools-shared/src/frontend/types';
import {localStorageGetItem, localStorageSetItem} from './storage';
import {
localStorageGetItem,
localStorageSetItem,
sessionStorageGetItem,
sessionStorageSetItem,
} from './storage';
import {meta} from './hydration';
import isArray from './isArray';

Expand All @@ -62,6 +69,10 @@ import type {
} from 'react-devtools-shared/src/frontend/types';
import type {SerializedElement as SerializedElementBackend} from 'react-devtools-shared/src/backend/types';
import {isSynchronousXHRSupported} from './backend/utils';
import type {
ReloadAndProfileConfig,
ReloadAndProfileConfigPersistence,
} from './backend/types';

// $FlowFixMe[method-unbinding]
const hasOwnProperty = Object.prototype.hasOwnProperty;
Expand Down Expand Up @@ -978,3 +989,35 @@ export function getIsReloadAndProfileSupported(): boolean {

return isBackendStorageAPISupported && isSynchronousXHRSupported();
}

export const defaultReloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence =
{
setReloadAndProfileConfig({
shouldReloadAndProfile,
recordChangeDescriptions,
}): void {
if (shouldReloadAndProfile != null) {
sessionStorageSetItem(
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
shouldReloadAndProfile ? 'true' : 'false',
);
}
if (recordChangeDescriptions != null) {
sessionStorageSetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
recordChangeDescriptions ? 'true' : 'false',
);
}
},
getReloadAndProfileConfig(): ReloadAndProfileConfig {
return {
shouldReloadAndProfile:
sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) ===
'true',
recordChangeDescriptions:
sessionStorageGetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
) === 'true',
};
},
};

0 comments on commit 204a551

Please sign in to comment.