Skip to content

Commit a474aa8

Browse files
committed
refactor: allow custom impl of backend realod-to-profile support check
1 parent d66fa02 commit a474aa8

File tree

8 files changed

+57
-60
lines changed

8 files changed

+57
-60
lines changed

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

+15-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import {installHook} from 'react-devtools-shared/src/hook';
1313
import {initBackend} from 'react-devtools-shared/src/backend';
1414
import {__DEBUG__} from 'react-devtools-shared/src/constants';
1515
import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
16-
import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils';
16+
import {
17+
getDefaultComponentFilters,
18+
getIsReloadAndProfileSupported,
19+
} from 'react-devtools-shared/src/utils';
1720

1821
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
1922
import type {
@@ -36,6 +39,7 @@ type ConnectOptions = {
3639
isAppActive?: () => boolean,
3740
websocket?: ?WebSocket,
3841
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
42+
isReloadAndProfileSupported?: boolean,
3943
};
4044

4145
let savedComponentFilters: Array<ComponentFilter> =
@@ -77,6 +81,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
7781
retryConnectionDelay = 2000,
7882
isAppActive = () => true,
7983
onSettingsUpdated,
84+
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
8085
} = options || {};
8186

8287
const protocol = useHttps ? 'wss' : 'ws';
@@ -184,7 +189,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
184189
hook.emit('shutdown');
185190
});
186191

187-
initBackend(hook, agent, window);
192+
initBackend(hook, agent, window, isReloadAndProfileSupported);
188193

189194
// Setup React Native style editor if the environment supports it.
190195
if (resolveRNStyle != null || hook.resolveRNStyle != null) {
@@ -309,6 +314,7 @@ type ConnectWithCustomMessagingOptions = {
309314
nativeStyleEditorValidAttributes?: $ReadOnlyArray<string>,
310315
resolveRNStyle?: ResolveNativeStyle,
311316
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
317+
isReloadAndProfileSupported?: boolean,
312318
};
313319

314320
export function connectWithCustomMessagingProtocol({
@@ -318,6 +324,7 @@ export function connectWithCustomMessagingProtocol({
318324
nativeStyleEditorValidAttributes,
319325
resolveRNStyle,
320326
onSettingsUpdated,
327+
isReloadAndProfileSupported = getIsReloadAndProfileSupported(),
321328
}: ConnectWithCustomMessagingOptions): Function {
322329
const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
323330
if (hook == null) {
@@ -368,7 +375,12 @@ export function connectWithCustomMessagingProtocol({
368375
hook.emit('shutdown');
369376
});
370377

371-
const unsubscribeBackend = initBackend(hook, agent, window);
378+
const unsubscribeBackend = initBackend(
379+
hook,
380+
agent,
381+
window,
382+
isReloadAndProfileSupported,
383+
);
372384

373385
const nativeStyleResolver: ResolveNativeStyle | void =
374386
resolveRNStyle || hook.resolveRNStyle;

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
} from 'react-devtools-shared/src/backend/types';
1414
import {hasAssignedBackend} from 'react-devtools-shared/src/backend/utils';
1515
import {COMPACT_VERSION_NAME} from 'react-devtools-extensions/src/utils';
16+
import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils';
1617

1718
let welcomeHasInitialized = false;
1819

@@ -140,7 +141,7 @@ function activateBackend(version: string, hook: DevToolsHook) {
140141
hook.emit('shutdown');
141142
});
142143

143-
initBackend(hook, agent, window);
144+
initBackend(hook, agent, window, getIsReloadAndProfileSupported());
144145

145146
// Setup React Native style editor if a renderer like react-native-web has injected it.
146147
if (typeof setupNativeStyleEditor === 'function' && hook.resolveRNStyle) {

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ 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';
1112

1213
function startActivation(contentWindow: any, bridge: BackendBridge) {
1314
const onSavedPreferences = (data: $FlowFixMe) => {
@@ -66,7 +67,7 @@ function finishActivation(contentWindow: any, bridge: BackendBridge) {
6667

6768
const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__;
6869
if (hook) {
69-
initBackend(hook, agent, contentWindow);
70+
initBackend(hook, agent, contentWindow, getIsReloadAndProfileSupported());
7071

7172
// Setup React Native style editor if a renderer like react-native-web has injected it.
7273
if (hook.resolveRNStyle) {

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

+5-11
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

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function initBackend(
1717
hook: DevToolsHook,
1818
agent: Agent,
1919
global: Object,
20+
isReloadAndProfileSupported: boolean,
2021
): () => void {
2122
if (hook == null) {
2223
// DevTools didn't get injected into this page (maybe b'c of the contentType).
@@ -94,6 +95,10 @@ export function initBackend(
9495
}
9596
});
9697

98+
if (isReloadAndProfileSupported) {
99+
agent.onReloadAndProfileSupportedByHost();
100+
}
101+
97102
return () => {
98103
subs.forEach(fn => fn());
99104
};

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

+1-2
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

+14-42
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;
@@ -234,7 +226,7 @@ export default class Store extends EventEmitter<{
234226
this._supportsClickToInspect = true;
235227
}
236228
if (supportsReloadAndProfile) {
237-
this._supportsReloadAndProfile = true;
229+
this._isReloadAndProfileFrontendSupported = true;
238230
}
239231
if (supportsTimeline) {
240232
this._supportsTimeline = true;
@@ -255,17 +247,13 @@ export default class Store extends EventEmitter<{
255247
);
256248
bridge.addListener('shutdown', this.onBridgeShutdown);
257249
bridge.addListener(
258-
'isBackendStorageAPISupported',
259-
this.onBackendStorageAPISupported,
250+
'isReloadAndProfileSupportedByBackend',
251+
this.onBackendReloadAndProfileSupported,
260252
);
261253
bridge.addListener(
262254
'isNativeStyleEditorSupported',
263255
this.onBridgeNativeStyleEditorSupported,
264256
);
265-
bridge.addListener(
266-
'isSynchronousXHRSupported',
267-
this.onBridgeSynchronousXHRSupported,
268-
);
269257
bridge.addListener(
270258
'unsupportedRendererVersion',
271259
this.onBridgeUnsupportedRendererVersion,
@@ -469,13 +457,9 @@ export default class Store extends EventEmitter<{
469457
}
470458

471459
get supportsReloadAndProfile(): boolean {
472-
// Does the DevTools shell support reloading and eagerly injecting the renderer interface?
473-
// And if so, can the backend use the localStorage API and sync XHR?
474-
// All of these are currently required for the reload-and-profile feature to work.
475460
return (
476-
this._supportsReloadAndProfile &&
477-
this._isBackendStorageAPISupported &&
478-
this._isSynchronousXHRSupported
461+
this._isReloadAndProfileFrontendSupported &&
462+
this._isReloadAndProfileBackendSupported
479463
);
480464
}
481465

@@ -1433,17 +1417,13 @@ export default class Store extends EventEmitter<{
14331417
);
14341418
bridge.removeListener('shutdown', this.onBridgeShutdown);
14351419
bridge.removeListener(
1436-
'isBackendStorageAPISupported',
1437-
this.onBackendStorageAPISupported,
1420+
'isReloadAndProfileSupportedByBackend',
1421+
this.onBackendReloadAndProfileSupported,
14381422
);
14391423
bridge.removeListener(
14401424
'isNativeStyleEditorSupported',
14411425
this.onBridgeNativeStyleEditorSupported,
14421426
);
1443-
bridge.removeListener(
1444-
'isSynchronousXHRSupported',
1445-
this.onBridgeSynchronousXHRSupported,
1446-
);
14471427
bridge.removeListener(
14481428
'unsupportedRendererVersion',
14491429
this.onBridgeUnsupportedRendererVersion,
@@ -1458,18 +1438,10 @@ export default class Store extends EventEmitter<{
14581438
}
14591439
};
14601440

1461-
onBackendStorageAPISupported: (
1462-
isBackendStorageAPISupported: boolean,
1463-
) => void = isBackendStorageAPISupported => {
1464-
this._isBackendStorageAPISupported = isBackendStorageAPISupported;
1465-
1466-
this.emit('supportsReloadAndProfile');
1467-
};
1468-
1469-
onBridgeSynchronousXHRSupported: (
1470-
isSynchronousXHRSupported: boolean,
1471-
) => void = isSynchronousXHRSupported => {
1472-
this._isSynchronousXHRSupported = isSynchronousXHRSupported;
1441+
onBackendReloadAndProfileSupported: (
1442+
isReloadAndProfileSupported: boolean,
1443+
) => void = isReloadAndProfileSupported => {
1444+
this._isReloadAndProfileBackendSupported = isReloadAndProfileSupported;
14731445

14741446
this.emit('supportsReloadAndProfile');
14751447
};

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

+13
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import type {
6161
LRUCache,
6262
} from 'react-devtools-shared/src/frontend/types';
6363
import type {SerializedElement as SerializedElementBackend} from 'react-devtools-shared/src/backend/types';
64+
import {isSynchronousXHRSupported} from './backend/utils';
6465

6566
// $FlowFixMe[method-unbinding]
6667
const hasOwnProperty = Object.prototype.hasOwnProperty;
@@ -965,3 +966,15 @@ export function backendToFrontendSerializedElementMapper(
965966
export function normalizeUrl(url: string): string {
966967
return url.replace('/./', '/');
967968
}
969+
970+
export function getIsReloadAndProfileSupported(): boolean {
971+
// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
972+
// If not, features like reload-and-profile will not work correctly and must be disabled.
973+
let isBackendStorageAPISupported = false;
974+
try {
975+
localStorage.getItem('test');
976+
isBackendStorageAPISupported = true;
977+
} catch (error) {}
978+
979+
return isBackendStorageAPISupported && isSynchronousXHRSupported();
980+
}

0 commit comments

Comments
 (0)