Skip to content

Commit

Permalink
refactor: allow custom impl of backend realod-to-profile support check
Browse files Browse the repository at this point in the history
  • Loading branch information
EdmondChuiHW committed Sep 24, 2024
1 parent 04bd67a commit 95a4552
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 55 deletions.
19 changes: 19 additions & 0 deletions packages/react-devtools-core/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {
DevToolsHookSettings,
} from 'react-devtools-shared/src/backend/types';
import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
import {isSynchronousXHRSupported} from 'react-devtools-shared/src/backend/utils';

type ConnectOptions = {
host?: string,
Expand All @@ -36,6 +37,7 @@ type ConnectOptions = {
isAppActive?: () => boolean,
websocket?: ?WebSocket,
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
isReloadAndProfileSupported?: () => boolean,
};

let savedComponentFilters: Array<ComponentFilter> =
Expand All @@ -52,6 +54,18 @@ function debug(methodName: string, ...args: Array<mixed>) {
}
}

function defaultIsReloadAndProfileSupported() {
// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
// If not, features like reload-and-profile will not work correctly and must be disabled.
let isBackendStorageAPISupported = false;
try {
localStorage.getItem('test');
isBackendStorageAPISupported = true;
} catch (error) {}

return isBackendStorageAPISupported && isSynchronousXHRSupported();
}

export function initialize(
maybeSettingsOrSettingsPromise?:
| DevToolsHookSettings
Expand All @@ -77,6 +91,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
retryConnectionDelay = 2000,
isAppActive = () => true,
onSettingsUpdated,
isReloadAndProfileSupported = defaultIsReloadAndProfileSupported,
} = options || {};

const protocol = useHttps ? 'wss' : 'ws';
Expand Down Expand Up @@ -171,6 +186,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
// $FlowFixMe[incompatible-call] found when upgrading Flow
const agent = new Agent(bridge);
bridge?.send('isReloadAndProfileSupported', isReloadAndProfileSupported());
if (onSettingsUpdated != null) {
agent.addListener('updateHookSettings', onSettingsUpdated);
}
Expand Down Expand Up @@ -309,6 +325,7 @@ type ConnectWithCustomMessagingOptions = {
nativeStyleEditorValidAttributes?: $ReadOnlyArray<string>,
resolveRNStyle?: ResolveNativeStyle,
onSettingsUpdated?: (settings: $ReadOnly<DevToolsHookSettings>) => void,
isReloadAndProfileSupported?: () => boolean,
};

export function connectWithCustomMessagingProtocol({
Expand All @@ -318,6 +335,7 @@ export function connectWithCustomMessagingProtocol({
nativeStyleEditorValidAttributes,
resolveRNStyle,
onSettingsUpdated,
isReloadAndProfileSupported = defaultIsReloadAndProfileSupported,
}: ConnectWithCustomMessagingOptions): Function {
const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook == null) {
Expand Down Expand Up @@ -355,6 +373,7 @@ export function connectWithCustomMessagingProtocol({
}

const agent = new Agent(bridge);
bridge.send('isReloadAndProfileSupported', isReloadAndProfileSupported());
if (onSettingsUpdated != null) {
agent.addListener('updateHookSettings', onSettingsUpdated);
}
Expand Down
12 changes: 1 addition & 11 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import type {
DevToolsHookSettings,
} from './types';
import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types';
import {isSynchronousXHRSupported, isReactNativeEnvironment} from './utils';
import {isReactNativeEnvironment} from './utils';

const debug = (methodName: string, ...args: Array<string>) => {
if (__DEBUG__) {
Expand Down Expand Up @@ -242,16 +242,6 @@ export default class Agent extends EventEmitter<{
if (this._isProfiling) {
bridge.send('profilingStatus', true);
}

// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
// If not, features like reload-and-profile will not work correctly and must be disabled.
let isBackendStorageAPISupported = false;
try {
localStorage.getItem('test');
isBackendStorageAPISupported = true;
} catch (error) {}
bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported);
bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported());
}

get rendererInterfaces(): {[key: RendererID]: RendererInterface, ...} {
Expand Down
3 changes: 1 addition & 2 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ export type BackendEvents = {
fastRefreshScheduled: [],
getSavedPreferences: [],
inspectedElement: [InspectedElementPayload],
isBackendStorageAPISupported: [boolean],
isSynchronousXHRSupported: [boolean],
isReloadAndProfileSupported: [boolean],
operations: [Array<number>],
ownersList: [OwnersList],
overrideComponentFilters: [Array<ComponentFilter>],
Expand Down
56 changes: 14 additions & 42 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,6 @@ export default class Store extends EventEmitter<{
// Should the React Native style editor panel be shown?
_isNativeStyleEditorSupported: boolean = false;

// Can the backend use the Storage API (e.g. localStorage)?
// If not, features like reload-and-profile will not work correctly and must be disabled.
_isBackendStorageAPISupported: boolean = false;

// Can DevTools use sync XHR requests?
// If not, features like reload-and-profile will not work correctly and must be disabled.
// This current limitation applies only to web extension builds
// and will need to be reconsidered in the future if we add support for reload to React Native.
_isSynchronousXHRSupported: boolean = false;

_nativeStyleEditorValidAttributes: $ReadOnlyArray<string> | null = null;

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

_isReloadAndProfileFrontendSupported: boolean = false;
_isReloadAndProfileBackendSupported: boolean = false;

// These options default to false but may be updated as roots are added and removed.
_rootSupportsBasicProfiling: boolean = false;
_rootSupportsTimelineProfiling: boolean = false;
Expand Down Expand Up @@ -233,7 +225,7 @@ export default class Store extends EventEmitter<{
this._supportsClickToInspect = true;
}
if (supportsReloadAndProfile) {
this._supportsReloadAndProfile = true;
this._isReloadAndProfileFrontendSupported = true;
}
if (supportsTimeline) {
this._supportsTimeline = true;
Expand All @@ -254,17 +246,13 @@ export default class Store extends EventEmitter<{
);
bridge.addListener('shutdown', this.onBridgeShutdown);
bridge.addListener(
'isBackendStorageAPISupported',
this.onBackendStorageAPISupported,
'isReloadAndProfileSupported',
this.onBackendReloadAndProfileSupported,
);
bridge.addListener(
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.addListener(
'isSynchronousXHRSupported',
this.onBridgeSynchronousXHRSupported,
);
bridge.addListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
Expand Down Expand Up @@ -452,13 +440,9 @@ export default class Store extends EventEmitter<{
}

get supportsReloadAndProfile(): boolean {
// Does the DevTools shell support reloading and eagerly injecting the renderer interface?
// And if so, can the backend use the localStorage API and sync XHR?
// All of these are currently required for the reload-and-profile feature to work.
return (
this._supportsReloadAndProfile &&
this._isBackendStorageAPISupported &&
this._isSynchronousXHRSupported
this._isReloadAndProfileFrontendSupported &&
this._isReloadAndProfileBackendSupported
);
}

Expand Down Expand Up @@ -1407,17 +1391,13 @@ export default class Store extends EventEmitter<{
);
bridge.removeListener('shutdown', this.onBridgeShutdown);
bridge.removeListener(
'isBackendStorageAPISupported',
this.onBackendStorageAPISupported,
'isReloadAndProfileSupported',
this.onBackendReloadAndProfileSupported,
);
bridge.removeListener(
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.removeListener(
'isSynchronousXHRSupported',
this.onBridgeSynchronousXHRSupported,
);
bridge.removeListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
Expand All @@ -1432,18 +1412,10 @@ export default class Store extends EventEmitter<{
}
};

onBackendStorageAPISupported: (
isBackendStorageAPISupported: boolean,
) => void = isBackendStorageAPISupported => {
this._isBackendStorageAPISupported = isBackendStorageAPISupported;

this.emit('supportsReloadAndProfile');
};

onBridgeSynchronousXHRSupported: (
isSynchronousXHRSupported: boolean,
) => void = isSynchronousXHRSupported => {
this._isSynchronousXHRSupported = isSynchronousXHRSupported;
onBackendReloadAndProfileSupported: (
isReloadAndProfileSupported: boolean,
) => void = isReloadAndProfileSupported => {
this._isReloadAndProfileBackendSupported = isReloadAndProfileSupported;

this.emit('supportsReloadAndProfile');
};
Expand Down

0 comments on commit 95a4552

Please sign in to comment.