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

DO NOT MERGE DevTools: Add Bridge protocol version backend/frontend #21344

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/react-devtools-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-devtools-core",
"version": "4.10.1",
"version": "4.10.2",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
5 changes: 4 additions & 1 deletion packages/react-devtools-core/src/standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ function initialize(socket: WebSocket) {
socket.close();
});

store = new Store(bridge, {supportsNativeInspection: false});
store = new Store(bridge, {
checkBridgeProtocolCompatibility: true,
supportsNativeInspection: false,
});

log('Connected');
reload();
Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Chrome Developer Tools.",
"version": "4.10.1",
"version_name": "4.10.1",
"version": "4.10.2",
"version_name": "4.10.2",

"minimum_chrome_version": "49",

Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/edge/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Microsoft Edge Developer Tools.",
"version": "4.10.1",
"version_name": "4.10.1",
"version": "4.10.2",
"version_name": "4.10.2",

"minimum_chrome_version": "49",

Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-extensions/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Firefox Developer Tools.",
"version": "4.10.1",
"version": "4.10.2",

"applications": {
"gecko": {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-inline/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-devtools-inline",
"version": "4.10.1",
"version": "4.10.2",
"description": "Embed react-devtools within a website",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
5 changes: 4 additions & 1 deletion packages/react-devtools-inline/src/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ export function initialize(
},
});

const store: Store = new Store(bridge, {supportsTraceUpdates: true});
const store: Store = new Store(bridge, {
checkBridgeProtocolCompatibility: true,
supportsTraceUpdates: true,
});

const ForwardRef = forwardRef<Props, mixed>((props, ref) => (
<DevTools ref={ref} bridge={bridge} store={store} {...props} />
Expand Down
15 changes: 15 additions & 0 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ import type {StyleAndLayout as StyleAndLayoutPayload} from 'react-devtools-share

const BATCH_DURATION = 100;

// This message specifies the version of the DevTools protocol currently supported by the backend,
// as well as the earliest NPM version (e.g. "4.13.0") that protocol is supported by on the frontend.
// This enables an older frontend to display an upgrade message to users for a newer, unsupported backend.
export type BridgeProtocol = {|
// Version supported by the current frontend/backend.
version: number,

// NPM version range that also supports this version.
// Note that 'maxNpmVersion' is only set when the version is bumped.
minNpmVersion: string,
maxNpmVersion: string | null,
|};

type ElementAndRendererID = {|id: number, rendererID: RendererID|};

type Message = {|
Expand Down Expand Up @@ -117,6 +130,7 @@ type UpdateConsolePatchSettingsParams = {|
|};

type BackendEvents = {|
bridgeProtocol: [BridgeProtocol],
extensionBackendInitialized: [],
inspectedElement: [InspectedElementPayload],
isBackendStorageAPISupported: [boolean],
Expand Down Expand Up @@ -144,6 +158,7 @@ type FrontendEvents = {|
clearNativeElementHighlight: [],
copyElementPath: [CopyElementPathParams],
deletePath: [DeletePath],
getBridgeProtocol: [],
getOwnersList: [ElementAndRendererID],
getProfilingData: [{|rendererID: RendererID|}],
getProfilingStatus: [],
Expand Down
25 changes: 24 additions & 1 deletion packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import ProfilerStore from './ProfilerStore';

import type {Element} from './views/Components/types';
import type {ComponentFilter, ElementType} from '../types';
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type {
BridgeProtocol,
FrontendBridge,
} from 'react-devtools-shared/src/bridge';

const debug = (methodName, ...args) => {
if (__DEBUG__) {
Expand All @@ -49,6 +52,7 @@ const LOCAL_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY =
'React::DevTools::recordChangeDescriptions';

type Config = {|
checkBridgeProtocolCompatibility?: boolean,
isProfiling?: boolean,
supportsNativeInspection?: boolean,
supportsReloadAndProfile?: boolean,
Expand All @@ -74,6 +78,7 @@ export default class Store extends EventEmitter<{|
supportsNativeStyleEditor: [],
supportsProfiling: [],
supportsReloadAndProfile: [],
unsupportedBridgeProtocolDetected: [],
unsupportedRendererVersionDetected: [],
|}> {
_bridge: FrontendBridge;
Expand Down Expand Up @@ -128,6 +133,7 @@ export default class Store extends EventEmitter<{|
_supportsReloadAndProfile: boolean = false;
_supportsTraceUpdates: boolean = false;

_unsupportedBridgeProtocol: BridgeProtocol | null = null;
_unsupportedRendererVersionDetected: boolean = false;

// Total number of visible elements (within all roots).
Expand Down Expand Up @@ -194,6 +200,13 @@ export default class Store extends EventEmitter<{|
);

this._profilerStore = new ProfilerStore(bridge, this, isProfiling);

// Verify that the frontend version is compatible with the connected backend.
// See github.com/facebook/react/issues/21326
if (config != null && config.checkBridgeProtocolCompatibility) {
bridge.addListener('bridgeProtocol', this.onBridgeProtocol);
bridge.send('getBridgeProtocol');
}
}

// This is only used in tests to avoid memory leaks.
Expand Down Expand Up @@ -353,6 +366,10 @@ export default class Store extends EventEmitter<{|
return this._supportsTraceUpdates;
}

get unsupportedBridgeProtocol(): BridgeProtocol | null {
return this._unsupportedBridgeProtocol;
}

get unsupportedRendererVersionDetected(): boolean {
return this._unsupportedRendererVersionDetected;
}
Expand Down Expand Up @@ -1020,6 +1037,7 @@ export default class Store extends EventEmitter<{|
'isBackendStorageAPISupported',
this.onBridgeStorageSupported,
);
this._bridge.removeListener('bridgeProtocol', this.onBridgeProtocol);
};

onBridgeStorageSupported = (isBackendStorageAPISupported: boolean) => {
Expand All @@ -1033,4 +1051,9 @@ export default class Store extends EventEmitter<{|

this.emit('unsupportedRendererVersionDetected');
};

onBridgeProtocol = (bridgeProtocol: BridgeProtocol) => {
this._unsupportedBridgeProtocol = bridgeProtocol;
this.emit('unsupportedBridgeProtocolDetected');
};
}
2 changes: 2 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/DevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import ViewElementSourceContext from './Components/ViewElementSourceContext';
import {ProfilerContextController} from './Profiler/ProfilerContext';
import {ModalDialogContextController} from './ModalDialog';
import ReactLogo from './ReactLogo';
import UnsupportedBridgeProtocolDialog from './UnsupportedBridgeProtocolDialog';
import UnsupportedVersionDialog from './UnsupportedVersionDialog';
import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';
import {useLocalStorage} from './hooks';
Expand Down Expand Up @@ -226,6 +227,7 @@ export default function DevTools({
</TreeContextController>
</ViewElementSourceContext.Provider>
</SettingsContextController>
<UnsupportedBridgeProtocolDialog />
{warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
{warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
</ModalDialogContextController>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,13 @@ export function updateThemeVariables(
updateStyleHelper(theme, 'color-expand-collapse-toggle', documentElements);
updateStyleHelper(theme, 'color-link', documentElements);
updateStyleHelper(theme, 'color-modal-background', documentElements);
updateStyleHelper(
theme,
'color-bridge-version-npm-background',
documentElements,
);
updateStyleHelper(theme, 'color-bridge-version-npm-text', documentElements);
updateStyleHelper(theme, 'color-bridge-version-number', documentElements);
updateStyleHelper(theme, 'color-record-active', documentElements);
updateStyleHelper(theme, 'color-record-hover', documentElements);
updateStyleHelper(theme, 'color-record-inactive', documentElements);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.Column {
display: flex;
flex-direction: column;
}

.Title {
font-size: var(--font-size-sans-large);
margin-bottom: 0.5rem;
}

.ReleaseNotesLink {
color: var(--color-button-active);
}

.Version {
color: var(--color-bridge-version-number);
font-weight: bold;
}

.NpmCommand {
display: flex;
justify-content: space-between;
padding: 0.25rem 0.25rem 0.25rem 0.5rem;
background-color: var(--color-bridge-version-npm-background);
color: var(--color-bridge-version-npm-text);
margin: 0;
font-family: var(--font-family-monospace);
font-size: var(--font-size-monospace-large);
}

.Paragraph {
margin: 0.5rem 0;
}

.Link {
color: var(--color-link);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import * as React from 'react';
import {Fragment, useContext, useEffect, useState} from 'react';
import {unstable_batchedUpdates as batchedUpdates} from 'react-dom';
import {ModalDialogContext} from './ModalDialog';
import {StoreContext} from './context';
import Button from './Button';
import ButtonIcon from './ButtonIcon';
import {copy} from 'clipboard-js';
import styles from './UnsupportedBridgeProtocolDialog.css';

import type {BridgeProtocol} from 'react-devtools-shared/src/bridge';

type DAILOG_STATE = 'dialog-not-shown' | 'show-dialog' | 'dialog-shown';

const DEVTOOLS_VERSION = process.env.DEVTOOLS_VERSION;
const INSTRUCTIONS_FB_URL = 'https://fburl.com/devtools-bridge-protocol';

export default function UnsupportedBridgeProtocolDialog(_: {||}) {
const {dispatch} = useContext(ModalDialogContext);
const store = useContext(StoreContext);
const [state, setState] = useState<DAILOG_STATE>('dialog-not-shown');

useEffect(() => {
if (state === 'dialog-not-shown') {
const showDialog = () => {
batchedUpdates(() => {
setState('show-dialog');
dispatch({
canBeDismissed: false,
type: 'SHOW',
content: (
<DialogContent
unsupportedBridgeProtocol={store.unsupportedBridgeProtocol}
/>
),
});
});
};

if (store.unsupportedBridgeProtocol !== null) {
showDialog();
} else {
store.addListener('unsupportedBridgeProtocolDetected', showDialog);
return () => {
store.removeListener('unsupportedBridgeProtocolDetected', showDialog);
};
}
}
}, [state, store]);

return null;
}

function DialogContent({
unsupportedBridgeProtocol,
}: {|
unsupportedBridgeProtocol: BridgeProtocol,
|}) {
const {version, minNpmVersion} = unsupportedBridgeProtocol;
const upgradeInstructions = `npm i -g react-devtools@^${minNpmVersion}`;
return (
<Fragment>
<div className={styles.Column}>
<div className={styles.Title}>Unsupported DevTools backend version</div>
<p className={styles.Paragraph}>
You are running <code>react-devtools</code> version{' '}
<span className={styles.Version}>{DEVTOOLS_VERSION}</span>.
</p>
<p className={styles.Paragraph}>
This requires bridge protocol{' '}
<span className={styles.Version}>version 0</span>. However the current
backend version uses bridge protocol{' '}
<span className={styles.Version}>version {version}</span>.
</p>
<p className={styles.Paragraph}>
To fix this, upgrade the DevTools NPM package:
</p>
<pre className={styles.NpmCommand}>
{upgradeInstructions}
<Button
onClick={() => copy(upgradeInstructions)}
title="Copy upgrade command to clipboard">
<ButtonIcon type="copy" />
</Button>
</pre>
<p className={styles.Paragraph}>
Or{' '}
<a
data-electron-external-link="true"
className={styles.Link}
href={INSTRUCTIONS_FB_URL}
target="_blank">
click here
</a>{' '}
for more information.
</p>
</div>
</Fragment>
);
}
6 changes: 6 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/root.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
--light-color-expand-collapse-toggle: #777d88;
--light-color-link: #0000ff;
--light-color-modal-background: rgba(255, 255, 255, 0.75);
--light-color-bridge-version-npm-background: #eff0f1;
--light-color-bridge-version-npm-text: #000000;
--light-color-bridge-version-number: #0088fa;
--light-color-record-active: #fc3a4b;
--light-color-record-hover: #3578e5;
--light-color-record-inactive: #0088fa;
Expand Down Expand Up @@ -136,6 +139,9 @@
--dark-color-expand-collapse-toggle: #8f949d;
--dark-color-link: #61dafb;
--dark-color-modal-background: rgba(0, 0, 0, 0.75);
--dark-color-bridge-version-npm-background: rgba(0, 0, 0, 0.25);
--dark-color-bridge-version-npm-text: #ffffff;
--dark-color-bridge-version-number: yellow;
--dark-color-record-active: #fc3a4b;
--dark-color-record-hover: #a2e9fc;
--dark-color-record-inactive: #61dafb;
Expand Down
6 changes: 6 additions & 0 deletions packages/react-devtools/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ app.on('ready', function() {
},
});

// https://stackoverflow.com/questions/32402327/
mainWindow.webContents.on('new-window', function(event, url) {
event.preventDefault();
require('electron').shell.openExternal(url);
});

// and load the index.html of the app.
mainWindow.loadURL('file://' + __dirname + '/app.html'); // eslint-disable-line no-path-concat
mainWindow.webContents.executeJavaScript(
Expand Down
Loading