Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure sync-xhr is allowed before reload and profile #20879

Merged
merged 13 commits into from
Mar 11, 2021
Merged
2 changes: 2 additions & 0 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import type {
RendererInterface,
} from './types';
import type {ComponentFilter} from '../types';
import {isSynchronousXHRSupported} from './utils';

const debug = (methodName, ...args) => {
if (__DEBUG__) {
Expand Down Expand Up @@ -221,6 +222,7 @@ export default class Agent extends EventEmitter<{|
isBackendStorageAPISupported = true;
} catch (error) {}
bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported);
bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported());

setupHighlighter(bridge, this);
setupTraceUpdates(this);
Expand Down
8 changes: 8 additions & 0 deletions packages/react-devtools-shared/src/backend/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,11 @@ export function format(

return '' + formatted;
}

export function isSynchronousXHRSupported(): boolean {
return !!(
window.document &&
window.document.featurePolicy &&
bvaughn marked this conversation as resolved.
Show resolved Hide resolved
window.document.featurePolicy.allowsFeature('sync-xhr')
);
}
1 change: 1 addition & 0 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export type BackendEvents = {|
extensionBackendInitialized: [],
inspectedElement: [InspectedElementPayload],
isBackendStorageAPISupported: [boolean],
isSynchronousXHRSupported: [boolean],
operations: [Array<number>],
ownersList: [OwnersList],
overrideComponentFilters: [Array<ComponentFilter>],
Expand Down
56 changes: 47 additions & 9 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ export default class Store extends EventEmitter<{|
// 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;

// Map of element (id) to the set of elements (ids) it owns.
Expand Down Expand Up @@ -195,12 +201,16 @@ export default class Store extends EventEmitter<{|
bridge.addListener('shutdown', this.onBridgeShutdown);
bridge.addListener(
'isBackendStorageAPISupported',
this.onBridgeStorageSupported,
this.onBackendStorageAPISupported,
);
bridge.addListener(
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.addListener(
'isSynchronousXHRSupported',
this.onBridgeSynchronousXHRSupported,
);
bridge.addListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
Expand Down Expand Up @@ -359,11 +369,16 @@ export default class Store extends EventEmitter<{|
get supportsProfiling(): boolean {
return this._supportsProfiling;
}

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?
// Both of these are required for the reload-and-profile feature to work.
return this._supportsReloadAndProfile && this._isBackendStorageAPISupported;
// 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
);
}

get supportsTraceUpdates(): boolean {
Expand Down Expand Up @@ -1130,20 +1145,43 @@ export default class Store extends EventEmitter<{|
debug('onBridgeShutdown', 'unsubscribing from Bridge');
}

this._bridge.removeListener('operations', this.onBridgeOperations);
this._bridge.removeListener('shutdown', this.onBridgeShutdown);
this._bridge.removeListener(
const bridge = this._bridge;
bridge.removeListener('operations', this.onBridgeOperations);
bridge.removeListener(
'overrideComponentFilters',
this.onBridgeOverrideComponentFilters,
);
bridge.removeListener('shutdown', this.onBridgeShutdown);
bridge.removeListener(
'isBackendStorageAPISupported',
this.onBridgeStorageSupported,
this.onBackendStorageAPISupported,
);
bridge.removeListener(
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.removeListener(
'isSynchronousXHRSupported',
this.onBridgeSynchronousXHRSupported,
);
bridge.removeListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
);
};

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

this.emit('supportsReloadAndProfile');
};

onBridgeSynchronousXHRSupported = (isSynchronousXHRSupported: boolean) => {
this._isSynchronousXHRSupported = isSynchronousXHRSupported;

this.emit('supportsReloadAndProfile');
};

onBridgeUnsupportedRendererVersion = () => {
this._unsupportedRendererVersionDetected = true;

Expand Down