Skip to content

Commit bfe91fb

Browse files
authored
refactor[react-devtools]: flatten reload and profile config (#31132)
Stacked on #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.
1 parent 1d8d120 commit bfe91fb

10 files changed

Lines changed: 131 additions & 99 deletions

File tree

packages/react-devtools-core/src/backend.js

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ import type {
2626
import type {
2727
DevToolsHook,
2828
DevToolsHookSettings,
29-
ReloadAndProfileConfig,
30-
ReloadAndProfileConfigPersistence,
29+
ProfilingSettings,
3130
} from 'react-devtools-shared/src/backend/types';
3231
import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
3332

@@ -42,7 +41,9 @@ type ConnectOptions = {
4241
websocket?: ?WebSocket,
4342
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
4443
isReloadAndProfileSupported?: boolean,
45-
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence,
44+
isProfiling?: boolean,
45+
onReloadAndProfile?: (recordChangeDescriptions: boolean) => void,
46+
onReloadAndProfileFlagsReset?: () => void,
4647
};
4748

4849
let savedComponentFilters: Array<ComponentFilter> =
@@ -63,9 +64,15 @@ export function initialize(
6364
maybeSettingsOrSettingsPromise?:
6465
| DevToolsHookSettings
6566
| Promise<DevToolsHookSettings>,
66-
reloadAndProfileConfig?: ReloadAndProfileConfig,
67+
shouldStartProfilingNow: boolean = false,
68+
profilingSettings?: ProfilingSettings,
6769
) {
68-
installHook(window, maybeSettingsOrSettingsPromise, reloadAndProfileConfig);
70+
installHook(
71+
window,
72+
maybeSettingsOrSettingsPromise,
73+
shouldStartProfilingNow,
74+
profilingSettings,
75+
);
6976
}
7077

7178
export function connectToDevTools(options: ?ConnectOptions) {
@@ -86,7 +93,9 @@ export function connectToDevTools(options: ?ConnectOptions) {
8693
isAppActive = () => true,
8794
onSettingsUpdated,
8895
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
89-
reloadAndProfileConfigPersistence,
96+
isProfiling,
97+
onReloadAndProfile,
98+
onReloadAndProfileFlagsReset,
9099
} = options || {};
91100

92101
const protocol = useHttps ? 'wss' : 'ws';
@@ -180,7 +189,11 @@ export function connectToDevTools(options: ?ConnectOptions) {
180189

181190
// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
182191
// $FlowFixMe[incompatible-call] found when upgrading Flow
183-
const agent = new Agent(bridge, reloadAndProfileConfigPersistence);
192+
const agent = new Agent(bridge, isProfiling, onReloadAndProfile);
193+
if (typeof onReloadAndProfileFlagsReset === 'function') {
194+
onReloadAndProfileFlagsReset();
195+
}
196+
184197
if (onSettingsUpdated != null) {
185198
agent.addListener('updateHookSettings', onSettingsUpdated);
186199
}
@@ -320,7 +333,9 @@ type ConnectWithCustomMessagingOptions = {
320333
resolveRNStyle?: ResolveNativeStyle,
321334
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
322335
isReloadAndProfileSupported?: boolean,
323-
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence,
336+
isProfiling?: boolean,
337+
onReloadAndProfile?: (recordChangeDescriptions: boolean) => void,
338+
onReloadAndProfileFlagsReset?: () => void,
324339
};
325340

326341
export function connectWithCustomMessagingProtocol({
@@ -331,7 +346,9 @@ export function connectWithCustomMessagingProtocol({
331346
resolveRNStyle,
332347
onSettingsUpdated,
333348
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
334-
reloadAndProfileConfigPersistence,
349+
isProfiling,
350+
onReloadAndProfile,
351+
onReloadAndProfileFlagsReset,
335352
}: ConnectWithCustomMessagingOptions): Function {
336353
const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
337354
if (hook == null) {
@@ -368,7 +385,11 @@ export function connectWithCustomMessagingProtocol({
368385
bridge.send('overrideComponentFilters', savedComponentFilters);
369386
}
370387

371-
const agent = new Agent(bridge, reloadAndProfileConfigPersistence);
388+
const agent = new Agent(bridge, isProfiling, onReloadAndProfile);
389+
if (typeof onReloadAndProfileFlagsReset === 'function') {
390+
onReloadAndProfileFlagsReset();
391+
}
392+
372393
if (onSettingsUpdated != null) {
373394
agent.addListener('updateHookSettings', onSettingsUpdated);
374395
}

packages/react-devtools-extensions/src/contentScripts/backendManager.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import type {
1414
import {hasAssignedBackend} from 'react-devtools-shared/src/backend/utils';
1515
import {COMPACT_VERSION_NAME} from 'react-devtools-extensions/src/utils';
1616
import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils';
17+
import {
18+
getIfReloadedAndProfiling,
19+
onReloadAndProfile,
20+
onReloadAndProfileFlagsReset,
21+
} from 'react-devtools-shared/src/utils';
1722

1823
let welcomeHasInitialized = false;
1924
const requiredBackends = new Set<string>();
@@ -140,7 +145,15 @@ function activateBackend(version: string, hook: DevToolsHook) {
140145
},
141146
});
142147

143-
const agent = new Agent(bridge);
148+
const agent = new Agent(
149+
bridge,
150+
getIfReloadedAndProfiling(),
151+
onReloadAndProfile,
152+
);
153+
// Agent read flags successfully, we can count it as successful launch
154+
// Clean up flags, so that next reload won't start profiling
155+
onReloadAndProfileFlagsReset();
156+
144157
agent.addListener('shutdown', () => {
145158
// If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down,
146159
// and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here.

packages/react-devtools-extensions/src/contentScripts/installHook.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import {installHook} from 'react-devtools-shared/src/hook';
2+
import {
3+
getIfReloadedAndProfiling,
4+
getProfilingSettings,
5+
} from 'react-devtools-shared/src/utils';
26

37
let resolveHookSettingsInjection;
48

@@ -34,8 +38,15 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
3438
payload: {handshake: true},
3539
});
3640

41+
const shouldStartProfiling = getIfReloadedAndProfiling();
42+
const profilingSettings = getProfilingSettings();
3743
// Can't delay hook installation, inject settings lazily
38-
installHook(window, hookSettingsPromise);
44+
installHook(
45+
window,
46+
hookSettingsPromise,
47+
shouldStartProfiling,
48+
profilingSettings,
49+
);
3950

4051
// Detect React
4152
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on(

packages/react-devtools-inline/src/backend.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyl
88

99
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
1010
import type {Wall} from 'react-devtools-shared/src/frontend/types';
11-
import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils';
11+
import {
12+
getIfReloadedAndProfiling,
13+
getIsReloadAndProfileSupported,
14+
onReloadAndProfile,
15+
onReloadAndProfileFlagsReset,
16+
} from 'react-devtools-shared/src/utils';
1217

1318
function startActivation(contentWindow: any, bridge: BackendBridge) {
1419
const onSavedPreferences = (data: $FlowFixMe) => {
@@ -63,7 +68,12 @@ function startActivation(contentWindow: any, bridge: BackendBridge) {
6368
}
6469

6570
function finishActivation(contentWindow: any, bridge: BackendBridge) {
66-
const agent = new Agent(bridge);
71+
const agent = new Agent(
72+
bridge,
73+
getIfReloadedAndProfiling(),
74+
onReloadAndProfile,
75+
);
76+
onReloadAndProfileFlagsReset();
6777

6878
const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__;
6979
if (hook) {

packages/react-devtools-shared/src/attachRenderer.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import type {
1212
RendererInterface,
1313
DevToolsHook,
1414
RendererID,
15+
ProfilingSettings,
1516
} from 'react-devtools-shared/src/backend/types';
16-
import type {ReloadAndProfileConfig} from './backend/types';
1717

1818
import {attach as attachFlight} from 'react-devtools-shared/src/backend/flight/renderer';
1919
import {attach as attachFiber} from 'react-devtools-shared/src/backend/fiber/renderer';
@@ -30,7 +30,8 @@ export default function attachRenderer(
3030
id: RendererID,
3131
renderer: ReactRenderer,
3232
global: Object,
33-
reloadAndProfileConfig: ReloadAndProfileConfig,
33+
shouldStartProfilingNow: boolean,
34+
profilingSettings: ProfilingSettings,
3435
): RendererInterface | void {
3536
// only attach if the renderer is compatible with the current version of the backend
3637
if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) {
@@ -55,7 +56,8 @@ export default function attachRenderer(
5556
id,
5657
renderer,
5758
global,
58-
reloadAndProfileConfig,
59+
shouldStartProfilingNow,
60+
profilingSettings,
5961
);
6062
} else if (renderer.ComponentTree) {
6163
// react-dom v15

packages/react-devtools-shared/src/backend/agent.js

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ import type {
2626
RendererID,
2727
RendererInterface,
2828
DevToolsHookSettings,
29-
ReloadAndProfileConfigPersistence,
3029
} from './types';
3130
import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
3231
import {isReactNativeEnvironment} from './utils';
33-
import {defaultReloadAndProfileConfigPersistence} from '../utils';
3432
import {
3533
sessionStorageGetItem,
3634
sessionStorageRemoveItem,
@@ -151,33 +149,21 @@ export default class Agent extends EventEmitter<{
151149
}> {
152150
_bridge: BackendBridge;
153151
_isProfiling: boolean = false;
154-
_recordChangeDescriptions: boolean = false;
155152
_rendererInterfaces: {[key: RendererID]: RendererInterface, ...} = {};
156153
_persistedSelection: PersistedSelection | null = null;
157154
_persistedSelectionMatch: PathMatch | null = null;
158155
_traceUpdatesEnabled: boolean = false;
159-
_reloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence;
156+
_onReloadAndProfile: ((recordChangeDescriptions: boolean) => void) | void;
160157

161158
constructor(
162159
bridge: BackendBridge,
163-
reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence = defaultReloadAndProfileConfigPersistence,
160+
isProfiling: boolean = false,
161+
onReloadAndProfile?: (recordChangeDescriptions: boolean) => void,
164162
) {
165163
super();
166164

167-
this._reloadAndProfileConfigPersistence = reloadAndProfileConfigPersistence;
168-
const {getReloadAndProfileConfig, setReloadAndProfileConfig} =
169-
reloadAndProfileConfigPersistence;
170-
const reloadAndProfileConfig = getReloadAndProfileConfig();
171-
if (reloadAndProfileConfig.shouldReloadAndProfile) {
172-
this._recordChangeDescriptions =
173-
reloadAndProfileConfig.recordChangeDescriptions;
174-
this._isProfiling = true;
175-
176-
setReloadAndProfileConfig({
177-
shouldReloadAndProfile: false,
178-
recordChangeDescriptions: false,
179-
});
180-
}
165+
this._isProfiling = isProfiling;
166+
this._onReloadAndProfile = onReloadAndProfile;
181167

182168
const persistedSelectionString = sessionStorageGetItem(
183169
SESSION_STORAGE_LAST_SELECTION_KEY,
@@ -674,10 +660,9 @@ export default class Agent extends EventEmitter<{
674660

675661
reloadAndProfile: (recordChangeDescriptions: boolean) => void =
676662
recordChangeDescriptions => {
677-
this._reloadAndProfileConfigPersistence.setReloadAndProfileConfig({
678-
shouldReloadAndProfile: true,
679-
recordChangeDescriptions,
680-
});
663+
if (typeof this._onReloadAndProfile === 'function') {
664+
this._onReloadAndProfile(recordChangeDescriptions);
665+
}
681666

682667
// This code path should only be hit if the shell has explicitly told the Store that it supports profiling.
683668
// In that case, the shell must also listen for this specific message to know when it needs to reload the app.
@@ -757,7 +742,6 @@ export default class Agent extends EventEmitter<{
757742

758743
startProfiling: (recordChangeDescriptions: boolean) => void =
759744
recordChangeDescriptions => {
760-
this._recordChangeDescriptions = recordChangeDescriptions;
761745
this._isProfiling = true;
762746
for (const rendererID in this._rendererInterfaces) {
763747
const renderer = ((this._rendererInterfaces[
@@ -770,7 +754,6 @@ export default class Agent extends EventEmitter<{
770754

771755
stopProfiling: () => void = () => {
772756
this._isProfiling = false;
773-
this._recordChangeDescriptions = false;
774757
for (const rendererID in this._rendererInterfaces) {
775758
const renderer = ((this._rendererInterfaces[
776759
(rendererID: any)

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ import {
104104
supportsOwnerStacks,
105105
supportsConsoleTasks,
106106
} from './DevToolsFiberComponentStack';
107-
import type {ReloadAndProfileConfig} from '../types';
108107

109108
// $FlowFixMe[method-unbinding]
110109
const toString = Object.prototype.toString;
@@ -136,6 +135,7 @@ import type {
136135
WorkTagMap,
137136
CurrentDispatcherRef,
138137
LegacyDispatcherRef,
138+
ProfilingSettings,
139139
} from '../types';
140140
import type {
141141
ComponentFilter,
@@ -864,7 +864,8 @@ export function attach(
864864
rendererID: number,
865865
renderer: ReactRenderer,
866866
global: Object,
867-
reloadAndProfileConfig: ReloadAndProfileConfig,
867+
shouldStartProfilingNow: boolean,
868+
profilingSettings: ProfilingSettings,
868869
): RendererInterface {
869870
// Newer versions of the reconciler package also specific reconciler version.
870871
// If that version number is present, use it.
@@ -5225,10 +5226,8 @@ export function attach(
52255226
}
52265227

52275228
// Automatically start profiling so that we don't miss timing info from initial "mount".
5228-
if (reloadAndProfileConfig.shouldReloadAndProfile) {
5229-
const shouldRecordChangeDescriptions =
5230-
reloadAndProfileConfig.recordChangeDescriptions;
5231-
startProfiling(shouldRecordChangeDescriptions);
5229+
if (shouldStartProfilingNow) {
5230+
startProfiling(profilingSettings.recordChangeDescriptions);
52325231
}
52335232

52345233
function getNearestFiber(devtoolsInstance: DevToolsInstance): null | Fiber {

packages/react-devtools-shared/src/backend/types.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -485,20 +485,10 @@ export type DevToolsBackend = {
485485
setupNativeStyleEditor?: SetupNativeStyleEditor,
486486
};
487487

488-
export type ReloadAndProfileConfig = {
489-
shouldReloadAndProfile: boolean,
488+
export type ProfilingSettings = {
490489
recordChangeDescriptions: boolean,
491490
};
492491

493-
// Linter doesn't speak Flow's `Partial` type
494-
// eslint-disable-next-line no-undef
495-
type PartialReloadAndProfileConfig = Partial<ReloadAndProfileConfig>;
496-
497-
export type ReloadAndProfileConfigPersistence = {
498-
setReloadAndProfileConfig: (config: PartialReloadAndProfileConfig) => void,
499-
getReloadAndProfileConfig: () => ReloadAndProfileConfig,
500-
};
501-
502492
export type DevToolsHook = {
503493
listeners: {[key: string]: Array<Handler>, ...},
504494
rendererInterfaces: Map<RendererID, RendererInterface>,

0 commit comments

Comments
 (0)