Show status of connection, so that user knows what is happening
Summary: In many cases the React DevTools fail to show up for RN. usually that is because the app didn't enter devMode yet. This diff adds the necessary logic to query the state of the DevTools and communicate back the current connection status Reviewed By: passy Differential Revision: D19878127 fbshipit-source-id: f5c3f5a92b23c87c87d778a468122210325eed17
This commit is contained in:
committed by
Facebook Github Bot
parent
14ebfb8439
commit
3849807d6b
@@ -7,9 +7,8 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import ReactDevToolsStandalone from 'react-devtools-core/standalone';
|
||||
import {FlipperPlugin, AndroidDevice, styled} from 'flipper';
|
||||
import {FlipperPlugin, AndroidDevice, styled, View, Toolbar} from 'flipper';
|
||||
import React from 'react';
|
||||
import getPort from 'get-port';
|
||||
import address from 'address';
|
||||
@@ -19,6 +18,7 @@ const Container = styled.div({
|
||||
flex: '1 1 0%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'stretch',
|
||||
height: '100%',
|
||||
});
|
||||
|
||||
const DEV_TOOLS_NODE_ID = 'reactdevtools-out-of-react-node';
|
||||
@@ -43,7 +43,7 @@ function findDevToolsNode(): HTMLElement | null {
|
||||
}
|
||||
|
||||
function attachDevTools(target: Element | Text, devToolsNode: HTMLElement) {
|
||||
target.insertBefore(devToolsNode, target.childNodes[0]);
|
||||
target.appendChild(devToolsNode);
|
||||
devToolsNode.style.display = 'flex';
|
||||
}
|
||||
|
||||
@@ -52,27 +52,89 @@ function detachDevTools(devToolsNode: HTMLElement) {
|
||||
document.body && document.body.appendChild(devToolsNode);
|
||||
}
|
||||
|
||||
export default class extends FlipperPlugin<{}, any, {}> {
|
||||
const CONNECTED = 'DevTools connected';
|
||||
|
||||
export default class extends FlipperPlugin<
|
||||
{
|
||||
status: string;
|
||||
},
|
||||
any,
|
||||
{}
|
||||
> {
|
||||
pollHandle?: NodeJS.Timeout;
|
||||
containerRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
triedToAutoConnect = false;
|
||||
|
||||
state = {
|
||||
status: 'initializing',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
let devToolsNode = findDevToolsNode();
|
||||
if (!devToolsNode) {
|
||||
devToolsNode = createDevToolsNode();
|
||||
this.initializeDevTools(devToolsNode);
|
||||
} else {
|
||||
this.setStatus(
|
||||
'DevTools have been initialized, waiting for connection...',
|
||||
);
|
||||
if (devToolsNode.innerHTML) {
|
||||
this.setStatus(CONNECTED);
|
||||
} else {
|
||||
this.startPollForConnection();
|
||||
}
|
||||
}
|
||||
|
||||
const currentComponentNode = ReactDOM.findDOMNode(this);
|
||||
currentComponentNode && attachDevTools(currentComponentNode, devToolsNode);
|
||||
attachDevTools(this.containerRef?.current!, devToolsNode);
|
||||
this.startPollForConnection();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.pollHandle) {
|
||||
clearTimeout(this.pollHandle);
|
||||
}
|
||||
const devToolsNode = findDevToolsNode();
|
||||
devToolsNode && detachDevTools(devToolsNode);
|
||||
}
|
||||
|
||||
setStatus(status: string) {
|
||||
console.log(`[ReactDevtoolsPlugin] ${status}`);
|
||||
if (status.startsWith('The server is listening on')) {
|
||||
this.setState({status: status + ' Waiting for connection...'});
|
||||
} else {
|
||||
this.setState({status});
|
||||
}
|
||||
}
|
||||
|
||||
startPollForConnection() {
|
||||
this.pollHandle = setTimeout(() => {
|
||||
if (findDevToolsNode()?.innerHTML) {
|
||||
this.setStatus(CONNECTED);
|
||||
} else {
|
||||
if (!this.triedToAutoConnect) {
|
||||
this.triedToAutoConnect = true;
|
||||
this.setStatus(
|
||||
"The DevTools didn't connect yet. Please open the DevMenu or Reload to connect",
|
||||
);
|
||||
// TODO: send reload command
|
||||
}
|
||||
this.startPollForConnection();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
async initializeDevTools(devToolsNode: HTMLElement) {
|
||||
this.setStatus('Waiting for port 8097');
|
||||
const port = await getPort({port: 8097}); // default port for dev tools
|
||||
ReactDevToolsStandalone.setContentDOMNode(devToolsNode).startServer(port);
|
||||
this.setStatus('Starting DevTools server on ' + port);
|
||||
ReactDevToolsStandalone.setContentDOMNode(devToolsNode)
|
||||
.setStatusListener(status => {
|
||||
this.setStatus(status);
|
||||
})
|
||||
.startServer(port);
|
||||
this.setStatus('Waiting for device');
|
||||
const device = await this.getDevice();
|
||||
|
||||
if (device) {
|
||||
const host =
|
||||
device.deviceType === 'physical'
|
||||
@@ -80,16 +142,25 @@ export default class extends FlipperPlugin<{}, any, {}> {
|
||||
: device instanceof AndroidDevice
|
||||
? '10.0.2.2' // Host IP for Android emulator host system
|
||||
: 'localhost';
|
||||
this.setStatus(`Updating config to ${host}:${port}`);
|
||||
this.client.call('config', {port, host});
|
||||
|
||||
if (['quest', 'go', 'pacific'].includes(device.title.toLowerCase())) {
|
||||
const device = await this.getDevice();
|
||||
this.setStatus(`Setting up reverse port mapping: ${port}:${port}`);
|
||||
(device as AndroidDevice).reverse([port, port]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Container />;
|
||||
return (
|
||||
<View grow>
|
||||
{this.state.status !== CONNECTED ? (
|
||||
<Toolbar>{this.state.status}</Toolbar>
|
||||
) : null}
|
||||
<Container ref={this.containerRef} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
declare module 'react-devtools-core/standalone' {
|
||||
interface DevTools {
|
||||
setContentDOMNode(node: HTMLElement): DevTools;
|
||||
startServer(port: number): DevTools;
|
||||
setContentDOMNode(node: HTMLElement): this;
|
||||
startServer(port: number): this;
|
||||
setStatusListener(listener: (message: string) => void): this;
|
||||
}
|
||||
const DevTools: DevTools;
|
||||
export default DevTools;
|
||||
|
||||
Reference in New Issue
Block a user