From 934cd82941d2b4fa49e49517acd454a775fe94b8 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 14 Feb 2017 13:53:21 -0800 Subject: [PATCH] Move DevTools integration into its own repo Summary: The way React DevTools integration was set up in RN was not entirely supported by the React team, and we had to disable it in c3b25c9059f57ee8df5505628ff6221f11cf9234 so that we can move forward with enabling Fiber support in React Native. Here, I am moving the DevTools client setup from RN repo to [React DevTools repo](https://github.com/facebook/react-devtools/blob/master/packages/react-devtools-core/README.md#requirereact-devtools-coreconnecttodevtoolsoptions) so that we can keep it in sync with the rest of React DevTools. This is also a part of a larger effort to consolidate DevTools code (https://github.com/facebook/react-devtools/issues/489). It allows us to remove the double injection of the hook, an lets us replace the `eval` hack with a regular dependency. The implementation [lives here now](https://github.com/facebook/react-devtools/blob/master/packages/react-devtools-core/src/backend.js). This change re-enables Nuclide Inspector with React Native Stack reconciler and prepares it for compatibi Closes https://github.com/facebook/react-native/pull/12316 Reviewed By: zertosh Differential Revision: D4545322 Pulled By: gaearon fbshipit-source-id: ab949916c1a92c6b41cd41e7e1edf9697a71de2e --- Libraries/Core/Devtools/setupDevtools.js | 112 +++--------------- Libraries/Core/InitializeCore.js | 3 +- .../java/com/facebook/react/tests/BUCK | 1 + ...alystNativeJSToJavaParametersTestCase.java | 2 + ...talystNativeJavaToJSArgumentsTestCase.java | 2 + ...ystNativeJavaToJSReturnValuesTestCase.java | 2 + .../tests/CatalystUIManagerTestCase.java | 2 + .../facebook/react/tests/JSLocaleTest.java | 2 + .../react/tests/ProgressBarTestCase.java | 2 + .../react/tests/ViewRenderingTestCase.java | 2 + local-cli/server/runServer.js | 1 - package.json | 1 + 12 files changed, 35 insertions(+), 97 deletions(-) diff --git a/Libraries/Core/Devtools/setupDevtools.js b/Libraries/Core/Devtools/setupDevtools.js index 97e9240b0..57777c7c7 100644 --- a/Libraries/Core/Devtools/setupDevtools.js +++ b/Libraries/Core/Devtools/setupDevtools.js @@ -11,100 +11,24 @@ */ 'use strict'; -var NativeModules = require('NativeModules'); -var Platform = require('Platform'); +if (__DEV__) { + var AppState = require('AppState'); + var NativeModules = require('NativeModules'); + var Platform = require('Platform'); + var {connectToDevTools} = require('react-devtools-core'); -function setupDevtools() { - var messageListeners = []; - var closeListeners = []; - var hostname = 'localhost'; - if (Platform.OS === 'android' && NativeModules.AndroidConstants) { - hostname = NativeModules.AndroidConstants.ServerHost.split(':')[0]; - } - var port = window.__REACT_DEVTOOLS_PORT__ || 8097; - var ws = new window.WebSocket('ws://' + hostname + ':' + port + '/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)); - }, + connectToDevTools({ + isAppActive() { + // Don't steal the DevTools from currently active app. + return AppState.currentState !== 'background'; }, - }; - ws.onclose = handleClose; - ws.onerror = handleClose; - ws.onopen = function () { - tryToConnect(); - }; - - var hasClosed = false; - function handleClose() { - if (!hasClosed) { - hasClosed = true; - setTimeout(setupDevtools, 2000); - closeListeners.forEach(fn => fn()); - } - } - - 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; - } - ws.onmessage = handleMessage; - } - - function handleMessage(evt) { - // It's hard to handle JSON in a safe manner without inspecting it at - // runtime, hence the any - var data: any; - 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()); - 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; - } - }); - } + // Special case: Genymotion is running on a different host. + host: (Platform.OS === 'android' && NativeModules.AndroidConstants) ? + NativeModules.AndroidConstants.ServerHost.split(':')[0] : + 'localhost', + // Read the optional global variable for backward compatibility. + // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0. + port: window.__REACT_DEVTOOLS_PORT__, + resolveRNStyle: require('flattenStyle'), + }); } - -module.exports = setupDevtools; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index af8c053e0..092d17205 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -195,8 +195,7 @@ if (__DEV__) { // not when debugging in chrome // TODO(t12832058) This check is broken if (!window.document) { - const setupDevtools = require('setupDevtools'); - setupDevtools(); + require('setupDevtools'); } require('RCTDebugComponentOwnership'); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK index ba25f6008..ec1507940 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK @@ -9,6 +9,7 @@ deps = [ react_native_target('java/com/facebook/react/bridge:bridge'), react_native_target('java/com/facebook/react/common:common'), react_native_target('java/com/facebook/react/module/annotations:annotations'), + react_native_target('java/com/facebook/react/modules/appstate:appstate'), react_native_target('java/com/facebook/react/modules/core:core'), react_native_target('java/com/facebook/react/modules/datepicker:datepicker'), react_native_target('java/com/facebook/react/modules/share:share'), diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJSToJavaParametersTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJSToJavaParametersTestCase.java index d4b6734b9..ec2dcd5a8 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJSToJavaParametersTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJSToJavaParametersTestCase.java @@ -30,6 +30,7 @@ import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.UnexpectedNativeTypeException; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.testing.FakeWebSocketModule; import com.facebook.react.testing.ReactIntegrationTestCase; @@ -100,6 +101,7 @@ public class CatalystNativeJSToJavaParametersTestCase extends ReactIntegrationTe mCatalystInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mRecordingTestModule) .addNativeModule(new AndroidInfoModule()) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addNativeModule(mUIManager) .addJSModule(TestJSToJavaParametersModule.class) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSArgumentsTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSArgumentsTestCase.java index 1b377e56b..8d21e7f42 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSArgumentsTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSArgumentsTestCase.java @@ -19,6 +19,7 @@ import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.testing.AssertModule; import com.facebook.react.testing.FakeWebSocketModule; import com.facebook.react.testing.ReactIntegrationTestCase; @@ -77,6 +78,7 @@ public class CatalystNativeJavaToJSArgumentsTestCase extends ReactIntegrationTes mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mAssertModule) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(TestJavaToJSArgumentsModule.class) .addNativeModule(mUIManager) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSReturnValuesTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSReturnValuesTestCase.java index 7e586d106..236a51a0f 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSReturnValuesTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystNativeJavaToJSReturnValuesTestCase.java @@ -18,6 +18,7 @@ import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.testing.AssertModule; import com.facebook.react.testing.FakeWebSocketModule; @@ -118,6 +119,7 @@ public class CatalystNativeJavaToJSReturnValuesTestCase extends ReactIntegration mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mAssertModule) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(TestJavaToJSReturnValuesModule.class) .addNativeModule(mUIManager) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystUIManagerTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystUIManagerTestCase.java index 5345064b3..6f09e69af 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystUIManagerTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/CatalystUIManagerTestCase.java @@ -21,6 +21,7 @@ import android.widget.TextView; import com.facebook.react.ReactRootView; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.UIImplementation; @@ -95,6 +96,7 @@ public class CatalystUIManagerTestCase extends ReactIntegrationTestCase { jsModule = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(uiManager) .addNativeModule(new AndroidInfoModule()) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(UIManagerTestModule.class) .build() diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java index 498d587e6..67ccb8997 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/JSLocaleTest.java @@ -18,6 +18,7 @@ import com.facebook.react.testing.StringRecordingModule; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; @@ -61,6 +62,7 @@ public class JSLocaleTest extends ReactIntegrationTestCase { mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mStringRecordingModule) .addNativeModule(mUIManager) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(TestJSLocaleModule.class) .build(); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ProgressBarTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ProgressBarTestCase.java index 40cc0b8f5..9865ce343 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ProgressBarTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ProgressBarTestCase.java @@ -24,6 +24,7 @@ import com.facebook.react.ReactRootView; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.uimanager.UIImplementation; import com.facebook.react.uimanager.UIImplementationProvider; @@ -86,6 +87,7 @@ public class ProgressBarTestCase extends ReactIntegrationTestCase { mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mUIManager) .addNativeModule(new AndroidInfoModule()) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ProgressBarTestModule.class) .build(); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ViewRenderingTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ViewRenderingTestCase.java index 71e22fa99..4c84c7181 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ViewRenderingTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ViewRenderingTestCase.java @@ -19,6 +19,7 @@ import com.facebook.react.ReactRootView; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.UIImplementation; @@ -67,6 +68,7 @@ public class ViewRenderingTestCase extends ReactIntegrationTestCase { mCatalystInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(uiManager) .addNativeModule(new AndroidInfoModule()) + .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ViewRenderingTestModule.class) .build(); diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 33126329f..1ae3a6336 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -69,7 +69,6 @@ function runServer(args, config, readyCallback) { wsProxy = webSocketProxy.attachToServer(serverInstance, '/debugger-proxy'); ms = messageSocket.attachToServer(serverInstance, '/message'); - webSocketProxy.attachToServer(serverInstance, '/devtools'); inspectorProxy.attachToServer(serverInstance, '/inspector'); readyCallback(); } diff --git a/package.json b/package.json index 6c371bc21..9d02f447c 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "plist": "^1.2.0", "promise": "^7.1.1", "react-clone-referenced-element": "^1.0.1", + "react-devtools-core": "^2.0.8", "react-timer-mixin": "^0.13.2", "react-transform-hmr": "^1.0.4", "rebound": "^0.0.13",