Ensure sync-xhr is allowed before reload and profile (#20879)
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
Chris Dobson committed
Mar 11, 2021 at 15:31 UTC
bd245c1bab1a1f965cb51f5d01406a2770244930
4 files changed
+58
-9
packages/react-devtools-shared/src/backend/agent.js
+2
@@ -38,6 +38,7 @@ import type {
38
RendererInterface,
39
} from './types';
40
import type {ComponentFilter} from '../types';
41
+import {isSynchronousXHRSupported} from './utils';
42
43
const debug = (methodName, ...args) => {
44
if (__DEBUG__) {
@@ -221,6 +222,7 @@ export default class Agent extends EventEmitter<{|
222
isBackendStorageAPISupported = true;
223
} catch (error) {}
224
bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported);
225
+ bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported());
226
227
setupHighlighter(bridge, this);
228
setupTraceUpdates(this);
packages/react-devtools-shared/src/backend/utils.js
+8
@@ -183,3 +183,11 @@ export function format(
183
184
return '' + formatted;
185
}
186
+
187
+export function isSynchronousXHRSupported(): boolean {
188
+ return !!(
189
+ window.document &&
190
+ window.document.featurePolicy &&
191
+ window.document.featurePolicy.allowsFeature('sync-xhr')
192
+ );
193
+}
packages/react-devtools-shared/src/bridge.js
+1
@@ -122,6 +122,7 @@ export type BackendEvents = {|
122
extensionBackendInitialized: [],
123
inspectedElement: [InspectedElementPayload],
124
isBackendStorageAPISupported: [boolean],
125
+ isSynchronousXHRSupported: [boolean],
126
operations: [Array<number>],
127
ownersList: [OwnersList],
128
overrideComponentFilters: [Array<ComponentFilter>],
packages/react-devtools-shared/src/devtools/store.js
+47
-9
@@ -111,6 +111,12 @@ export default class Store extends EventEmitter<{|
111
// If not, features like reload-and-profile will not work correctly and must be disabled.
112
_isBackendStorageAPISupported: boolean = false;
113
114
+ // Can DevTools use sync XHR requests?
115
+ // If not, features like reload-and-profile will not work correctly and must be disabled.
116
+ // This current limitation applies only to web extension builds
117
+ // and will need to be reconsidered in the future if we add support for reload to React Native.
118
+ _isSynchronousXHRSupported: boolean = false;
119
+
120
_nativeStyleEditorValidAttributes: $ReadOnlyArray<string> | null = null;
121
122
// Map of element (id) to the set of elements (ids) it owns.
@@ -195,12 +201,16 @@ export default class Store extends EventEmitter<{|
201
bridge.addListener('shutdown', this.onBridgeShutdown);
202
bridge.addListener(
203
'isBackendStorageAPISupported',
198
- this.onBridgeStorageSupported,
204
+ this.onBackendStorageAPISupported,
205
);
206
bridge.addListener(
207
'isNativeStyleEditorSupported',
208
this.onBridgeNativeStyleEditorSupported,
209
);
210
+ bridge.addListener(
211
+ 'isSynchronousXHRSupported',
212
+ this.onBridgeSynchronousXHRSupported,
213
+ );
214
bridge.addListener(
215
'unsupportedRendererVersion',
216
this.onBridgeUnsupportedRendererVersion,
@@ -359,11 +369,16 @@ export default class Store extends EventEmitter<{|
369
get supportsProfiling(): boolean {
370
return this._supportsProfiling;
371
}
372
+
373
get supportsReloadAndProfile(): boolean {
374
// Does the DevTools shell support reloading and eagerly injecting the renderer interface?
364
- // And if so, can the backend use the localStorage API?
365
- // Both of these are required for the reload-and-profile feature to work.
366
- return this._supportsReloadAndProfile && this._isBackendStorageAPISupported;
375
+ // And if so, can the backend use the localStorage API and sync XHR?
376
+ // All of these are currently required for the reload-and-profile feature to work.
377
+ return (
378
+ this._supportsReloadAndProfile &&
379
+ this._isBackendStorageAPISupported &&
380
+ this._isSynchronousXHRSupported
381
+ );
382
}
383
384
get supportsTraceUpdates(): boolean {
@@ -1130,20 +1145,43 @@ export default class Store extends EventEmitter<{|
1145
debug('onBridgeShutdown', 'unsubscribing from Bridge');
1146
}
1147
1133
- this._bridge.removeListener('operations', this.onBridgeOperations);
1134
- this._bridge.removeListener('shutdown', this.onBridgeShutdown);
1135
- this._bridge.removeListener(
1148
+ const bridge = this._bridge;
1149
+ bridge.removeListener('operations', this.onBridgeOperations);
1150
+ bridge.removeListener(
1151
+ 'overrideComponentFilters',
1152
+ this.onBridgeOverrideComponentFilters,
1153
+ );
1154
+ bridge.removeListener('shutdown', this.onBridgeShutdown);
1155
+ bridge.removeListener(
1156
'isBackendStorageAPISupported',
1137
- this.onBridgeStorageSupported,
1157
+ this.onBackendStorageAPISupported,
1158
+ );
1159
+ bridge.removeListener(
1160
+ 'isNativeStyleEditorSupported',
1161
+ this.onBridgeNativeStyleEditorSupported,
1162
+ );
1163
+ bridge.removeListener(
1164
+ 'isSynchronousXHRSupported',
1165
+ this.onBridgeSynchronousXHRSupported,
1166
+ );
1167
+ bridge.removeListener(
1168
+ 'unsupportedRendererVersion',
1169
+ this.onBridgeUnsupportedRendererVersion,
1170
);
1171
};
1172
1141
- onBridgeStorageSupported = (isBackendStorageAPISupported: boolean) => {
1173
+ onBackendStorageAPISupported = (isBackendStorageAPISupported: boolean) => {
1174
this._isBackendStorageAPISupported = isBackendStorageAPISupported;
1175
1176
this.emit('supportsReloadAndProfile');
1177
};
1178
1179
+ onBridgeSynchronousXHRSupported = (isSynchronousXHRSupported: boolean) => {
1180
+ this._isSynchronousXHRSupported = isSynchronousXHRSupported;
1181
+
1182
+ this.emit('supportsReloadAndProfile');
1183
+ };
1184
+
1185
onBridgeUnsupportedRendererVersion = () => {
1186
this._unsupportedRendererVersionDetected = true;
1187