Skip to content

Commit 9a7cec7

Browse files
committed
refactor: allow custom impl of backend realod-to-profile support check
1 parent 04bd67a commit 9a7cec7

File tree

5 files changed

+49
-57
lines changed

5 files changed

+49
-57
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type ConnectOptions = {
3636
isAppActive?: () => boolean,
3737
websocket?: ?WebSocket,
3838
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
39+
getIsReloadAndProfileSupported?: () => boolean,
3940
};
4041

4142
let savedComponentFilters: Array<ComponentFilter> =
@@ -77,6 +78,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
7778
retryConnectionDelay = 2000,
7879
isAppActive = () => true,
7980
onSettingsUpdated,
81+
getIsReloadAndProfileSupported,
8082
} = options || {};
8183

8284
const protocol = useHttps ? 'wss' : 'ws';
@@ -184,7 +186,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
184186
hook.emit('shutdown');
185187
});
186188

187-
initBackend(hook, agent, window);
189+
initBackend(hook, agent, window, getIsReloadAndProfileSupported);
188190

189191
// Setup React Native style editor if the environment supports it.
190192
if (resolveRNStyle != null || hook.resolveRNStyle != null) {
@@ -309,6 +311,7 @@ type ConnectWithCustomMessagingOptions = {
309311
nativeStyleEditorValidAttributes?: $ReadOnlyArray<string>,
310312
resolveRNStyle?: ResolveNativeStyle,
311313
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
314+
getIsReloadAndProfileSupported?: () => boolean,
312315
};
313316

314317
export function connectWithCustomMessagingProtocol({
@@ -318,6 +321,7 @@ export function connectWithCustomMessagingProtocol({
318321
nativeStyleEditorValidAttributes,
319322
resolveRNStyle,
320323
onSettingsUpdated,
324+
getIsReloadAndProfileSupported,
321325
}: ConnectWithCustomMessagingOptions): Function {
322326
const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
323327
if (hook == null) {
@@ -368,7 +372,12 @@ export function connectWithCustomMessagingProtocol({
368372
hook.emit('shutdown');
369373
});
370374

371-
const unsubscribeBackend = initBackend(hook, agent, window);
375+
const unsubscribeBackend = initBackend(
376+
hook,
377+
agent,
378+
window,
379+
getIsReloadAndProfileSupported,
380+
);
372381

373382
const nativeStyleResolver: ResolveNativeStyle | void =
374383
resolveRNStyle || hook.resolveRNStyle;

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import type {
3838
DevToolsHookSettings,
3939
} from './types';
4040
import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
41-
import {isSynchronousXHRSupported, isReactNativeEnvironment} from './utils';
41+
import {isReactNativeEnvironment} from './utils';
4242

4343
const debug = (methodName: string, ...args: Array<string>) => {
4444
if (__DEBUG__) {
@@ -242,16 +242,6 @@ export default class Agent extends EventEmitter<{
242242
if (this._isProfiling) {
243243
bridge.send('profilingStatus', true);
244244
}
245-
246-
// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
247-
// If not, features like reload-and-profile will not work correctly and must be disabled.
248-
let isBackendStorageAPISupported = false;
249-
try {
250-
localStorage.getItem('test');
251-
isBackendStorageAPISupported = true;
252-
} catch (error) {}
253-
bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported);
254-
bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported());
255245
}
256246

257247
get rendererInterfaces(): {[key: RendererID]: RendererInterface, ...} {
@@ -675,6 +665,10 @@ export default class Agent extends EventEmitter<{
675665
}
676666
};
677667

668+
onReloadAndProfileSupportedByHost: () => void = () => {
669+
this._bridge.send('isReloadAndProfileSupportedByBackend', true);
670+
};
671+
678672
reloadAndProfile: (recordChangeDescriptions: boolean) => void =
679673
recordChangeDescriptions => {
680674
sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
import Agent from './agent';
1111

1212
import type {DevToolsHook, RendererID, RendererInterface} from './types';
13+
import {isSynchronousXHRSupported} from './utils';
1314

1415
export type InitBackend = typeof initBackend;
1516

1617
export function initBackend(
1718
hook: DevToolsHook,
1819
agent: Agent,
1920
global: Object,
21+
getIsReloadAndProfileSupported: () => boolean = defaultGetIsReloadAndProfileSupported,
2022
): () => void {
2123
if (hook == null) {
2224
// DevTools didn't get injected into this page (maybe b'c of the contentType).
@@ -94,7 +96,23 @@ export function initBackend(
9496
}
9597
});
9698

99+
if (getIsReloadAndProfileSupported()) {
100+
agent.onReloadAndProfileSupportedByHost();
101+
}
102+
97103
return () => {
98104
subs.forEach(fn => fn());
99105
};
100106
}
107+
108+
function defaultGetIsReloadAndProfileSupported(): boolean {
109+
// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
110+
// If not, features like reload-and-profile will not work correctly and must be disabled.
111+
let isBackendStorageAPISupported = false;
112+
try {
113+
localStorage.getItem('test');
114+
isBackendStorageAPISupported = true;
115+
} catch (error) {}
116+
117+
return isBackendStorageAPISupported && isSynchronousXHRSupported();
118+
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,7 @@ export type BackendEvents = {
181181
fastRefreshScheduled: [],
182182
getSavedPreferences: [],
183183
inspectedElement: [InspectedElementPayload],
184-
isBackendStorageAPISupported: [boolean],
185-
isSynchronousXHRSupported: [boolean],
184+
isReloadAndProfileSupportedByBackend: [boolean],
186185
operations: [Array<number>],
187186
ownersList: [OwnersList],
188187
overrideComponentFilters: [Array<ComponentFilter>],

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

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,6 @@ export default class Store extends EventEmitter<{
138138
// Should the React Native style editor panel be shown?
139139
_isNativeStyleEditorSupported: boolean = false;
140140

141-
// Can the backend use the Storage API (e.g. localStorage)?
142-
// If not, features like reload-and-profile will not work correctly and must be disabled.
143-
_isBackendStorageAPISupported: boolean = false;
144-
145-
// Can DevTools use sync XHR requests?
146-
// If not, features like reload-and-profile will not work correctly and must be disabled.
147-
// This current limitation applies only to web extension builds
148-
// and will need to be reconsidered in the future if we add support for reload to React Native.
149-
_isSynchronousXHRSupported: boolean = false;
150-
151141
_nativeStyleEditorValidAttributes: $ReadOnlyArray<string> | null = null;
152142

153143
// Older backends don't support an explicit bridge protocol,
@@ -178,10 +168,12 @@ export default class Store extends EventEmitter<{
178168
// These options may be initially set by a configuration option when constructing the Store.
179169
_supportsInspectMatchingDOMElement: boolean = false;
180170
_supportsClickToInspect: boolean = false;
181-
_supportsReloadAndProfile: boolean = false;
182171
_supportsTimeline: boolean = false;
183172
_supportsTraceUpdates: boolean = false;
184173

174+
_isReloadAndProfileFrontendSupported: boolean = false;
175+
_isReloadAndProfileBackendSupported: boolean = false;
176+
185177
// These options default to false but may be updated as roots are added and removed.
186178
_rootSupportsBasicProfiling: boolean = false;
187179
_rootSupportsTimelineProfiling: boolean = false;
@@ -233,7 +225,7 @@ export default class Store extends EventEmitter<{
233225
this._supportsClickToInspect = true;
234226
}
235227
if (supportsReloadAndProfile) {
236-
this._supportsReloadAndProfile = true;
228+
this._isReloadAndProfileFrontendSupported = true;
237229
}
238230
if (supportsTimeline) {
239231
this._supportsTimeline = true;
@@ -254,17 +246,13 @@ export default class Store extends EventEmitter<{
254246
);
255247
bridge.addListener('shutdown', this.onBridgeShutdown);
256248
bridge.addListener(
257-
'isBackendStorageAPISupported',
258-
this.onBackendStorageAPISupported,
249+
'isReloadAndProfileSupportedByBackend',
250+
this.onBackendReloadAndProfileSupported,
259251
);
260252
bridge.addListener(
261253
'isNativeStyleEditorSupported',
262254
this.onBridgeNativeStyleEditorSupported,
263255
);
264-
bridge.addListener(
265-
'isSynchronousXHRSupported',
266-
this.onBridgeSynchronousXHRSupported,
267-
);
268256
bridge.addListener(
269257
'unsupportedRendererVersion',
270258
this.onBridgeUnsupportedRendererVersion,
@@ -452,13 +440,9 @@ export default class Store extends EventEmitter<{
452440
}
453441

454442
get supportsReloadAndProfile(): boolean {
455-
// Does the DevTools shell support reloading and eagerly injecting the renderer interface?
456-
// And if so, can the backend use the localStorage API and sync XHR?
457-
// All of these are currently required for the reload-and-profile feature to work.
458443
return (
459-
this._supportsReloadAndProfile &&
460-
this._isBackendStorageAPISupported &&
461-
this._isSynchronousXHRSupported
444+
this._isReloadAndProfileFrontendSupported &&
445+
this._isReloadAndProfileBackendSupported
462446
);
463447
}
464448

@@ -1407,17 +1391,13 @@ export default class Store extends EventEmitter<{
14071391
);
14081392
bridge.removeListener('shutdown', this.onBridgeShutdown);
14091393
bridge.removeListener(
1410-
'isBackendStorageAPISupported',
1411-
this.onBackendStorageAPISupported,
1394+
'isReloadAndProfileSupportedByBackend',
1395+
this.onBackendReloadAndProfileSupported,
14121396
);
14131397
bridge.removeListener(
14141398
'isNativeStyleEditorSupported',
14151399
this.onBridgeNativeStyleEditorSupported,
14161400
);
1417-
bridge.removeListener(
1418-
'isSynchronousXHRSupported',
1419-
this.onBridgeSynchronousXHRSupported,
1420-
);
14211401
bridge.removeListener(
14221402
'unsupportedRendererVersion',
14231403
this.onBridgeUnsupportedRendererVersion,
@@ -1432,18 +1412,10 @@ export default class Store extends EventEmitter<{
14321412
}
14331413
};
14341414

1435-
onBackendStorageAPISupported: (
1436-
isBackendStorageAPISupported: boolean,
1437-
) => void = isBackendStorageAPISupported => {
1438-
this._isBackendStorageAPISupported = isBackendStorageAPISupported;
1439-
1440-
this.emit('supportsReloadAndProfile');
1441-
};
1442-
1443-
onBridgeSynchronousXHRSupported: (
1444-
isSynchronousXHRSupported: boolean,
1445-
) => void = isSynchronousXHRSupported => {
1446-
this._isSynchronousXHRSupported = isSynchronousXHRSupported;
1415+
onBackendReloadAndProfileSupported: (
1416+
isReloadAndProfileSupported: boolean,
1417+
) => void = isReloadAndProfileSupported => {
1418+
this._isReloadAndProfileBackendSupported = isReloadAndProfileSupported;
14471419

14481420
this.emit('supportsReloadAndProfile');
14491421
};

0 commit comments

Comments
 (0)