Skip to content

Commit 9e4af68

Browse files
author
Jared Forsyth
committed
[react-native] enable react devtools from JavascriptCore
1 parent 10ffe17 commit 9e4af68

File tree

4 files changed

+132
-10
lines changed

4 files changed

+132
-10
lines changed

Libraries/Devtools/setupDevtools.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule setupDevtools
10+
* @flow
11+
*/
12+
'use strict';
13+
14+
function setupDevtools() {
15+
var messageListeners = [];
16+
var closeListeners = [];
17+
var ws = new window.WebSocket('ws://localhost:8081/devtools');
18+
// this is accessed by the eval'd backend code
19+
var FOR_BACKEND = { // eslint-disable-line no-unused-vars
20+
resolveRNStyle: require('flattenStyle'),
21+
wall: {
22+
listen(fn) {
23+
messageListeners.push(fn);
24+
},
25+
onClose(fn) {
26+
closeListeners.push(fn);
27+
},
28+
send(data) {
29+
ws.send(JSON.stringify(data));
30+
},
31+
},
32+
};
33+
ws.onclose = () => {
34+
console.warn('devtools socket closed');
35+
closeListeners.forEach(fn => fn());
36+
};
37+
ws.onerror = error => {
38+
console.warn('devtools socket errored', error);
39+
closeListeners.forEach(fn => fn());
40+
};
41+
ws.onopen = function () {
42+
tryToConnect();
43+
};
44+
45+
function tryToConnect() {
46+
ws.send('attach:agent');
47+
var _interval = setInterval(() => ws.send('attach:agent'), 500);
48+
ws.onmessage = evt => {
49+
if (evt.data.indexOf('eval:') === 0) {
50+
clearInterval(_interval);
51+
initialize(evt.data.slice('eval:'.length));
52+
}
53+
};
54+
}
55+
56+
function initialize(text) {
57+
try {
58+
// FOR_BACKEND is used by the eval'd code
59+
eval(text); // eslint-disable-line no-eval
60+
} catch (e) {
61+
console.error('Failed to eval' + e.message);
62+
return;
63+
}
64+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
65+
CurrentOwner: require('ReactCurrentOwner'),
66+
InstanceHandles: require('ReactInstanceHandles'),
67+
Mount: require('ReactNativeMount'),
68+
Reconciler: require('ReactReconciler'),
69+
TextComponent: require('ReactNativeTextComponent'),
70+
});
71+
ws.onmessage = handleMessage;
72+
}
73+
74+
function handleMessage(evt) {
75+
var data;
76+
try {
77+
data = JSON.parse(evt.data);
78+
} catch (e) {
79+
return console.error('failed to parse json: ' + evt.data);
80+
}
81+
// the devtools closed
82+
if (data.$close || data.$error) {
83+
closeListeners.forEach(fn => fn());
84+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.emit('shutdown');
85+
tryToConnect();
86+
return;
87+
}
88+
if (data.$open) {
89+
return; // ignore
90+
}
91+
messageListeners.forEach(fn => {
92+
try {
93+
fn(data);
94+
} catch (e) {
95+
// jsc doesn't play so well with tracebacks that go into eval'd code,
96+
// so the stack trace here will stop at the `eval()` call. Getting the
97+
// message that caused the error is the best we can do for now.
98+
console.log(data);
99+
throw e;
100+
}
101+
});
102+
}
103+
}
104+
105+
module.exports = setupDevtools;

Libraries/Inspector/Inspector.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ var StyleSheet = require('StyleSheet');
2020
var UIManager = require('NativeModules').UIManager;
2121
var View = require('View');
2222

23-
var REACT_DEVTOOLS_HOOK: ?Object = typeof window !== 'undefined' ? window.__REACT_DEVTOOLS_GLOBAL_HOOK__ : null;
24-
25-
if (REACT_DEVTOOLS_HOOK) {
23+
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
2624
// required for devtools to be able to edit react native styles
27-
REACT_DEVTOOLS_HOOK.resolveRNStyle = require('flattenStyle');
25+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = require('flattenStyle');
2826
}
2927

3028
class Inspector extends React.Component {
@@ -43,12 +41,12 @@ class Inspector extends React.Component {
4341
}
4442

4543
componentDidMount() {
46-
if (REACT_DEVTOOLS_HOOK) {
44+
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
4745
this.attachToDevtools = this.attachToDevtools.bind(this);
48-
REACT_DEVTOOLS_HOOK.on('react-devtools', this.attachToDevtools);
46+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on('react-devtools', this.attachToDevtools);
4947
// if devtools is already started
50-
if (REACT_DEVTOOLS_HOOK.reactDevtoolsAgent) {
51-
this.attachToDevtools(REACT_DEVTOOLS_HOOK.reactDevtoolsAgent);
48+
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent) {
49+
this.attachToDevtools(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent);
5250
}
5351
}
5452
}
@@ -57,8 +55,8 @@ class Inspector extends React.Component {
5755
if (this._subs) {
5856
this._subs.map(fn => fn());
5957
}
60-
if (REACT_DEVTOOLS_HOOK) {
61-
REACT_DEVTOOLS_HOOK.off('react-devtools', this.attachToDevtools);
58+
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
59+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.off('react-devtools', this.attachToDevtools);
6260
}
6361
}
6462

Libraries/ReactIOS/renderApplication.ios.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ function renderApplication<D, P, S>(
6969
rootTag,
7070
'Expect to have a valid rootTag, instead got ', rootTag
7171
);
72+
// not when debugging in chrome
73+
if (__DEV__ && !window.document) {
74+
var setupDevtools = require('setupDevtools');
75+
setupDevtools();
76+
}
7277
React.render(
7378
<AppContainer rootTag={rootTag}>
7479
<RootComponent

packager/webSocketProxy.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,19 @@ function attachToServer(server, path) {
1717
});
1818
var clients = [];
1919

20+
function sendSpecial(message) {
21+
clients.forEach(function (cn) {
22+
try {
23+
cn.send(JSON.stringify(message));
24+
} catch(e) {
25+
console.warn('WARN: ' + e.message);
26+
}
27+
});
28+
}
29+
2030
wss.on('connection', function(ws) {
31+
var id = Math.random().toString(15).slice(10, 20);
32+
sendSpecial({$open: id});
2133
clients.push(ws);
2234

2335
var allClientsExcept = function(ws) {
@@ -26,10 +38,12 @@ function attachToServer(server, path) {
2638

2739
ws.onerror = function() {
2840
clients = allClientsExcept(ws);
41+
sendSpecial({$error: id});
2942
};
3043

3144
ws.onclose = function() {
3245
clients = allClientsExcept(ws);
46+
sendSpecial({$close: id});
3347
};
3448

3549
ws.on('message', function(message) {

0 commit comments

Comments
 (0)