[react-native] enable react devtools from JavascriptCore
This commit is contained in:
parent
10ffe170c2
commit
9e4af68d91
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @providesModule setupDevtools
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function setupDevtools() {
|
||||||
|
var messageListeners = [];
|
||||||
|
var closeListeners = [];
|
||||||
|
var ws = new window.WebSocket('ws://localhost:8081/devtools');
|
||||||
|
// this is accessed by the eval'd backend code
|
||||||
|
var FOR_BACKEND = { // eslint-disable-line no-unused-vars
|
||||||
|
resolveRNStyle: require('flattenStyle'),
|
||||||
|
wall: {
|
||||||
|
listen(fn) {
|
||||||
|
messageListeners.push(fn);
|
||||||
|
},
|
||||||
|
onClose(fn) {
|
||||||
|
closeListeners.push(fn);
|
||||||
|
},
|
||||||
|
send(data) {
|
||||||
|
ws.send(JSON.stringify(data));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.onclose = () => {
|
||||||
|
console.warn('devtools socket closed');
|
||||||
|
closeListeners.forEach(fn => fn());
|
||||||
|
};
|
||||||
|
ws.onerror = error => {
|
||||||
|
console.warn('devtools socket errored', error);
|
||||||
|
closeListeners.forEach(fn => fn());
|
||||||
|
};
|
||||||
|
ws.onopen = function () {
|
||||||
|
tryToConnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
function tryToConnect() {
|
||||||
|
ws.send('attach:agent');
|
||||||
|
var _interval = setInterval(() => ws.send('attach:agent'), 500);
|
||||||
|
ws.onmessage = evt => {
|
||||||
|
if (evt.data.indexOf('eval:') === 0) {
|
||||||
|
clearInterval(_interval);
|
||||||
|
initialize(evt.data.slice('eval:'.length));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize(text) {
|
||||||
|
try {
|
||||||
|
// FOR_BACKEND is used by the eval'd code
|
||||||
|
eval(text); // eslint-disable-line no-eval
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to eval' + e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
|
||||||
|
CurrentOwner: require('ReactCurrentOwner'),
|
||||||
|
InstanceHandles: require('ReactInstanceHandles'),
|
||||||
|
Mount: require('ReactNativeMount'),
|
||||||
|
Reconciler: require('ReactReconciler'),
|
||||||
|
TextComponent: require('ReactNativeTextComponent'),
|
||||||
|
});
|
||||||
|
ws.onmessage = handleMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMessage(evt) {
|
||||||
|
var data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(evt.data);
|
||||||
|
} catch (e) {
|
||||||
|
return console.error('failed to parse json: ' + evt.data);
|
||||||
|
}
|
||||||
|
// the devtools closed
|
||||||
|
if (data.$close || data.$error) {
|
||||||
|
closeListeners.forEach(fn => fn());
|
||||||
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.emit('shutdown');
|
||||||
|
tryToConnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.$open) {
|
||||||
|
return; // ignore
|
||||||
|
}
|
||||||
|
messageListeners.forEach(fn => {
|
||||||
|
try {
|
||||||
|
fn(data);
|
||||||
|
} catch (e) {
|
||||||
|
// jsc doesn't play so well with tracebacks that go into eval'd code,
|
||||||
|
// so the stack trace here will stop at the `eval()` call. Getting the
|
||||||
|
// message that caused the error is the best we can do for now.
|
||||||
|
console.log(data);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = setupDevtools;
|
|
@ -20,11 +20,9 @@ var StyleSheet = require('StyleSheet');
|
||||||
var UIManager = require('NativeModules').UIManager;
|
var UIManager = require('NativeModules').UIManager;
|
||||||
var View = require('View');
|
var View = require('View');
|
||||||
|
|
||||||
var REACT_DEVTOOLS_HOOK: ?Object = typeof window !== 'undefined' ? window.__REACT_DEVTOOLS_GLOBAL_HOOK__ : null;
|
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
||||||
|
|
||||||
if (REACT_DEVTOOLS_HOOK) {
|
|
||||||
// required for devtools to be able to edit react native styles
|
// required for devtools to be able to edit react native styles
|
||||||
REACT_DEVTOOLS_HOOK.resolveRNStyle = require('flattenStyle');
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = require('flattenStyle');
|
||||||
}
|
}
|
||||||
|
|
||||||
class Inspector extends React.Component {
|
class Inspector extends React.Component {
|
||||||
|
@ -43,12 +41,12 @@ class Inspector extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (REACT_DEVTOOLS_HOOK) {
|
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
||||||
this.attachToDevtools = this.attachToDevtools.bind(this);
|
this.attachToDevtools = this.attachToDevtools.bind(this);
|
||||||
REACT_DEVTOOLS_HOOK.on('react-devtools', this.attachToDevtools);
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on('react-devtools', this.attachToDevtools);
|
||||||
// if devtools is already started
|
// if devtools is already started
|
||||||
if (REACT_DEVTOOLS_HOOK.reactDevtoolsAgent) {
|
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent) {
|
||||||
this.attachToDevtools(REACT_DEVTOOLS_HOOK.reactDevtoolsAgent);
|
this.attachToDevtools(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +55,8 @@ class Inspector extends React.Component {
|
||||||
if (this._subs) {
|
if (this._subs) {
|
||||||
this._subs.map(fn => fn());
|
this._subs.map(fn => fn());
|
||||||
}
|
}
|
||||||
if (REACT_DEVTOOLS_HOOK) {
|
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
||||||
REACT_DEVTOOLS_HOOK.off('react-devtools', this.attachToDevtools);
|
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.off('react-devtools', this.attachToDevtools);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,11 @@ function renderApplication<D, P, S>(
|
||||||
rootTag,
|
rootTag,
|
||||||
'Expect to have a valid rootTag, instead got ', rootTag
|
'Expect to have a valid rootTag, instead got ', rootTag
|
||||||
);
|
);
|
||||||
|
// not when debugging in chrome
|
||||||
|
if (__DEV__ && !window.document) {
|
||||||
|
var setupDevtools = require('setupDevtools');
|
||||||
|
setupDevtools();
|
||||||
|
}
|
||||||
React.render(
|
React.render(
|
||||||
<AppContainer rootTag={rootTag}>
|
<AppContainer rootTag={rootTag}>
|
||||||
<RootComponent
|
<RootComponent
|
||||||
|
|
|
@ -17,7 +17,19 @@ function attachToServer(server, path) {
|
||||||
});
|
});
|
||||||
var clients = [];
|
var clients = [];
|
||||||
|
|
||||||
|
function sendSpecial(message) {
|
||||||
|
clients.forEach(function (cn) {
|
||||||
|
try {
|
||||||
|
cn.send(JSON.stringify(message));
|
||||||
|
} catch(e) {
|
||||||
|
console.warn('WARN: ' + e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
wss.on('connection', function(ws) {
|
wss.on('connection', function(ws) {
|
||||||
|
var id = Math.random().toString(15).slice(10, 20);
|
||||||
|
sendSpecial({$open: id});
|
||||||
clients.push(ws);
|
clients.push(ws);
|
||||||
|
|
||||||
var allClientsExcept = function(ws) {
|
var allClientsExcept = function(ws) {
|
||||||
|
@ -26,10 +38,12 @@ function attachToServer(server, path) {
|
||||||
|
|
||||||
ws.onerror = function() {
|
ws.onerror = function() {
|
||||||
clients = allClientsExcept(ws);
|
clients = allClientsExcept(ws);
|
||||||
|
sendSpecial({$error: id});
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = function() {
|
ws.onclose = function() {
|
||||||
clients = allClientsExcept(ws);
|
clients = allClientsExcept(ws);
|
||||||
|
sendSpecial({$close: id});
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.on('message', function(message) {
|
ws.on('message', function(message) {
|
||||||
|
|
Loading…
Reference in New Issue