mirror of
https://github.com/status-im/react-native.git
synced 2025-02-26 08:05:34 +00:00
Added support for JavaScript third-party debuggers
Summary:* Add ability to configure the app that should open when starting debugging axemclion discussed this feature with tadeuzagallo and martinbigio on: https://github.com/facebook/react-native/issues/5051 Closes https://github.com/facebook/react-native/pull/5683 Reviewed By: martinbigio Differential Revision: D2971497 Pulled By: mkonicek fb-gh-sync-id: 91c3ce68feed989658124bb96cb61d03dd032599 fbshipit-source-id: 91c3ce68feed989658124bb96cb61d03dd032599
This commit is contained in:
parent
b9396cd744
commit
4c8a9f0d00
@ -62,7 +62,7 @@ RCT_EXPORT_MODULE()
|
|||||||
_injectedObjects = [NSMutableDictionary new];
|
_injectedObjects = [NSMutableDictionary new];
|
||||||
[_socket setDelegateDispatchQueue:_jsQueue];
|
[_socket setDelegateDispatchQueue:_jsQueue];
|
||||||
|
|
||||||
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:_url];
|
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-js-devtools" relativeToURL:_url];
|
||||||
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
|
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
|
||||||
|
|
||||||
if (![self connectToProxy]) {
|
if (![self connectToProxy]) {
|
||||||
@ -82,7 +82,7 @@ RCT_EXPORT_MODULE()
|
|||||||
if (!runtimeIsReady) {
|
if (!runtimeIsReady) {
|
||||||
RCTLogError(@"Runtime is not ready for debugging.\n "
|
RCTLogError(@"Runtime is not ready for debugging.\n "
|
||||||
"- Make sure Packager server is running.\n"
|
"- Make sure Packager server is running.\n"
|
||||||
"- Make sure Chrome is running and not paused on a breakpoint or exception and try reloading again.");
|
"- Make sure the JavaScript Debugger is running and not paused on a breakpoint or exception and try reloading again.");
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ RCT_EXPORT_MODULE()
|
|||||||
[weakSelf.bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
[weakSelf.bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
||||||
}]];
|
}]];
|
||||||
|
|
||||||
_webSocketExecutorName = [_defaults objectForKey:@"websocket-executor-name"] ?: @"Chrome";
|
_webSocketExecutorName = [_defaults objectForKey:@"websocket-executor-name"] ?: @"JS Remotely";
|
||||||
|
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
@ -443,8 +443,8 @@ RCT_EXPORT_MODULE()
|
|||||||
[weakSelf reload];
|
[weakSelf reload];
|
||||||
}]];
|
}]];
|
||||||
|
|
||||||
Class chromeExecutorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
Class jsDebuggingExecutorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||||
if (!chromeExecutorClass) {
|
if (!jsDebuggingExecutorClass) {
|
||||||
[items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"%@ Debugger Unavailable", _webSocketExecutorName] handler:^{
|
[items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"%@ Debugger Unavailable", _webSocketExecutorName] handler:^{
|
||||||
UIAlertView *alert = RCTAlertView(
|
UIAlertView *alert = RCTAlertView(
|
||||||
[NSString stringWithFormat:@"%@ Debugger Unavailable", _webSocketExecutorName],
|
[NSString stringWithFormat:@"%@ Debugger Unavailable", _webSocketExecutorName],
|
||||||
@ -455,10 +455,10 @@ RCT_EXPORT_MODULE()
|
|||||||
[alert show];
|
[alert show];
|
||||||
}]];
|
}]];
|
||||||
} else {
|
} else {
|
||||||
BOOL isDebuggingInChrome = _executorClass && _executorClass == chromeExecutorClass;
|
BOOL isDebuggingJS = _executorClass && _executorClass == jsDebuggingExecutorClass;
|
||||||
NSString *debugTitleChrome = isDebuggingInChrome ? [NSString stringWithFormat:@"Disable %@ Debugging", _webSocketExecutorName] : [NSString stringWithFormat:@"Debug in %@", _webSocketExecutorName];
|
NSString *debugTitleJS = isDebuggingJS ? [NSString stringWithFormat:@"Disable %@ Debugging", _webSocketExecutorName] : [NSString stringWithFormat:@"Debug %@", _webSocketExecutorName];
|
||||||
[items addObject:[RCTDevMenuItem buttonItemWithTitle:debugTitleChrome handler:^{
|
[items addObject:[RCTDevMenuItem buttonItemWithTitle:debugTitleJS handler:^{
|
||||||
weakSelf.executorClass = isDebuggingInChrome ? Nil : chromeExecutorClass;
|
weakSelf.executorClass = isDebuggingJS ? Nil : jsDebuggingExecutorClass;
|
||||||
}]];
|
}]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ public abstract class JSBundleLoader {
|
|||||||
* This loader is used when proxy debugging is enabled. In that case there is no point in fetching
|
* This loader is used when proxy debugging is enabled. In that case there is no point in fetching
|
||||||
* the bundle from device as remote executor will have to do it anyway.
|
* the bundle from device as remote executor will have to do it anyway.
|
||||||
*
|
*
|
||||||
* @param proxySourceURL the URL to load the JS bundle from in Chrome
|
* @param proxySourceURL the URL to load the JS bundle from in the JavaScript proxy
|
||||||
* @param realSourceURL the URL to report as the source URL, e.g. for asset loading
|
* @param realSourceURL the URL to report as the source URL, e.g. for asset loading
|
||||||
*/
|
*/
|
||||||
public static JSBundleLoader createRemoteDebuggerBundleLoader(
|
public static JSBundleLoader createRemoteDebuggerBundleLoader(
|
||||||
|
@ -54,8 +54,8 @@ public class DevServerHelper {
|
|||||||
"http://%s/%s.bundle?platform=android&dev=%s&hot=%s&minify=%s";
|
"http://%s/%s.bundle?platform=android&dev=%s&hot=%s&minify=%s";
|
||||||
private static final String SOURCE_MAP_URL_FORMAT =
|
private static final String SOURCE_MAP_URL_FORMAT =
|
||||||
BUNDLE_URL_FORMAT.replaceFirst("\\.bundle", ".map");
|
BUNDLE_URL_FORMAT.replaceFirst("\\.bundle", ".map");
|
||||||
private static final String LAUNCH_CHROME_DEVTOOLS_COMMAND_URL_FORMAT =
|
private static final String LAUNCH_JS_DEVTOOLS_COMMAND_URL_FORMAT =
|
||||||
"http://%s/launch-chrome-devtools";
|
"http://%s/launch-js-devtools";
|
||||||
private static final String ONCHANGE_ENDPOINT_URL_FORMAT =
|
private static final String ONCHANGE_ENDPOINT_URL_FORMAT =
|
||||||
"http://%s/onchange";
|
"http://%s/onchange";
|
||||||
private static final String WEBSOCKET_PROXY_URL_FORMAT = "ws://%s/debugger-proxy?role=client";
|
private static final String WEBSOCKET_PROXY_URL_FORMAT = "ws://%s/debugger-proxy?role=client";
|
||||||
@ -366,13 +366,13 @@ public class DevServerHelper {
|
|||||||
return String.format(Locale.US, ONCHANGE_ENDPOINT_URL_FORMAT, getDebugServerHost());
|
return String.format(Locale.US, ONCHANGE_ENDPOINT_URL_FORMAT, getDebugServerHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createLaunchChromeDevtoolsCommandUrl() {
|
private String createLaunchJSDevtoolsCommandUrl() {
|
||||||
return String.format(LAUNCH_CHROME_DEVTOOLS_COMMAND_URL_FORMAT, getDebugServerHost());
|
return String.format(LAUNCH_JS_DEVTOOLS_COMMAND_URL_FORMAT, getDebugServerHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void launchChromeDevtools() {
|
public void launchJSDevtools() {
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(createLaunchChromeDevtoolsCommandUrl())
|
.url(createLaunchJSDevtoolsCommandUrl())
|
||||||
.build();
|
.build();
|
||||||
mClient.newCall(request).enqueue(new Callback() {
|
mClient.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
@ -398,7 +398,7 @@ public class DevServerHelper {
|
|||||||
|
|
||||||
public String getJSBundleURLForRemoteDebugging(String mainModuleName) {
|
public String getJSBundleURLForRemoteDebugging(String mainModuleName) {
|
||||||
// The host IP we use when connecting to the JS bundle server from the emulator is not the
|
// The host IP we use when connecting to the JS bundle server from the emulator is not the
|
||||||
// same as the one needed to connect to the same server from the Chrome proxy running on the
|
// same as the one needed to connect to the same server from the JavaScript proxy running on the
|
||||||
// host itself.
|
// host itself.
|
||||||
return createBundleURL(getHostForJSProxy(), mainModuleName, getDevMode(), getHMR(), getJSMinifyMode());
|
return createBundleURL(getHostForJSProxy(), mainModuleName, getDevMode(), getHMR(), getJSMinifyMode());
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
|||||||
if (DevServerHelper.getReloadAppAction(context).equals(action)) {
|
if (DevServerHelper.getReloadAppAction(context).equals(action)) {
|
||||||
if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
|
if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
|
||||||
mIsUsingJSProxy = true;
|
mIsUsingJSProxy = true;
|
||||||
mDevServerHelper.launchChromeDevtools();
|
mDevServerHelper.launchJSDevtools();
|
||||||
} else {
|
} else {
|
||||||
mIsUsingJSProxy = false;
|
mIsUsingJSProxy = false;
|
||||||
}
|
}
|
||||||
@ -584,7 +584,7 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
|||||||
private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
|
private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
|
||||||
// When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
|
// When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
|
||||||
// anyway
|
// anyway
|
||||||
mDevServerHelper.launchChromeDevtools();
|
mDevServerHelper.launchJSDevtools();
|
||||||
|
|
||||||
JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
|
JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="catalyst_reloadjs" project="catalyst" translatable="false">Reload JS</string>
|
<string name="catalyst_reloadjs" project="catalyst" translatable="false">Reload JS</string>
|
||||||
<string name="catalyst_debugjs" project="catalyst" translatable="false">Debug in Chrome</string>
|
<string name="catalyst_debugjs" project="catalyst" translatable="false">Debug JS Remotely</string>
|
||||||
<string name="catalyst_debugjs_off" project="catalyst" translatable="false">Stop Chrome Debugging</string>
|
<string name="catalyst_debugjs_off" project="catalyst" translatable="false">Stop JS Remotely Debugging</string>
|
||||||
<string name="catalyst_hot_module_replacement" project="catalyst" translatable="false">Enable Hot Reloading</string>
|
<string name="catalyst_hot_module_replacement" project="catalyst" translatable="false">Enable Hot Reloading</string>
|
||||||
<string name="catalyst_hot_module_replacement_off" project="catalyst" translatable="false">Disable Hot Reloading</string>
|
<string name="catalyst_hot_module_replacement_off" project="catalyst" translatable="false">Disable Hot Reloading</string>
|
||||||
<string name="catalyst_live_reload" project="catalyst" translatable="false">Enable Live Reload</string>
|
<string name="catalyst_live_reload" project="catalyst" translatable="false">Enable Live Reload</string>
|
||||||
|
@ -34,7 +34,7 @@ You can use `console.error` to display a full screen error on a red background.
|
|||||||
These boxes only appear when you're running your app in dev mode.
|
These boxes only appear when you're running your app in dev mode.
|
||||||
|
|
||||||
### Chrome Developer Tools
|
### Chrome Developer Tools
|
||||||
To debug the JavaScript code in Chrome, select `Debug in Chrome` from the developer menu. This will open a new tab at [http://localhost:8081/debugger-ui](http://localhost:8081/debugger-ui).
|
To debug the JavaScript code in Chrome, select `Debug JS Remotely` from the developer menu. This will open a new tab at [http://localhost:8081/debugger-ui](http://localhost:8081/debugger-ui).
|
||||||
|
|
||||||
In Chrome, press `⌘ + option + i` or select `View` → `Developer` → `Developer Tools` to toggle the developer tools console. Enable [Pause On Caught Exceptions](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511) for a better debugging experience.
|
In Chrome, press `⌘ + option + i` or select `View` → `Developer` → `Developer Tools` to toggle the developer tools console. Enable [Pause On Caught Exceptions](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511) for a better debugging experience.
|
||||||
|
|
||||||
@ -43,6 +43,9 @@ To debug on a real device:
|
|||||||
1. On iOS - open the file `RCTWebSocketExecutor.m` and change `localhost` to the IP address of your computer. Shake the device to open the development menu with the option to start debugging.
|
1. On iOS - open the file `RCTWebSocketExecutor.m` and change `localhost` to the IP address of your computer. Shake the device to open the development menu with the option to start debugging.
|
||||||
2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse tcp:8081 tcp:8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer.
|
2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse tcp:8081 tcp:8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer.
|
||||||
|
|
||||||
|
### Custom JavaScript debugger
|
||||||
|
To use a custom JavaScript debugger define the `REACT_DEBUGGER` environment variable to a command that will start your custom debugger. That variable will be read from the Packager process. If that environment variable is set, selecting `Debug JS Remotely` from the developer menu will execute that command instead of opening Chrome. The exact command to be executed is the contents of the REACT_DEBUGGER environment variable followed by the space separated paths of all project roots (e.g. If you set REACT_DEBUGGER="node /path/to/launchDebugger.js --port 2345 --type ReactNative" then the command "node /path/to/launchDebugger.js --port 2345 --type ReactNative /path/to/reactNative/app" will end up being executed). Custom debugger commands executed this way should be short-lived processes, and they shouldn't produce more than 200 kilobytes of output.
|
||||||
|
|
||||||
### Live Reload
|
### Live Reload
|
||||||
This option allows for your JS changes to trigger automatic reload on the connected device/emulator. To enable this option:
|
This option allows for your JS changes to trigger automatic reload on the connected device/emulator. To enable this option:
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var child_process = require('child_process');
|
||||||
var execFile = require('child_process').execFile;
|
var execFile = require('child_process').execFile;
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var opn = require('opn');
|
var opn = require('opn');
|
||||||
@ -24,7 +25,39 @@ function getChromeAppName() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(options, isDebuggerConnected) {
|
function launchChromeDevTools(port) {
|
||||||
|
var debuggerURL = 'http://localhost:' + port + '/debugger-ui';
|
||||||
|
console.log('Launching Dev Tools...');
|
||||||
|
opn(debuggerURL, {app: [getChromeAppName()]}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Google Chrome exited with error:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapePath(path) {
|
||||||
|
return '"' + path + '"'; // " Can escape paths with spaces in OS X, Windows, and *nix
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchDevTools(options, isChromeConnected) {
|
||||||
|
// Explicit config always wins
|
||||||
|
var customDebugger = process.env.REACT_DEBUGGER;
|
||||||
|
if (customDebugger) {
|
||||||
|
var projects = options.projectRoots.map(escapePath).join(' ');
|
||||||
|
var command = customDebugger + ' ' + projects;
|
||||||
|
console.log('Starting custom debugger by executing: ' + command);
|
||||||
|
child_process.exec(command, function (error, stdout, stderr) {
|
||||||
|
if (error !== null) {
|
||||||
|
console.log('Error while starting custom debugger: ' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (!isChromeConnected()) {
|
||||||
|
// Dev tools are not yet open; we need to open a session
|
||||||
|
launchChromeDevTools(options.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(options, isChromeConnected) {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
if (req.url === '/debugger-ui') {
|
if (req.url === '/debugger-ui') {
|
||||||
var debuggerPath = path.join(__dirname, '..', 'util', 'debugger.html');
|
var debuggerPath = path.join(__dirname, '..', 'util', 'debugger.html');
|
||||||
@ -41,18 +74,16 @@ module.exports = function(options, isDebuggerConnected) {
|
|||||||
'If you still need this, please let us know.'
|
'If you still need this, please let us know.'
|
||||||
);
|
);
|
||||||
} else if (req.url === '/launch-chrome-devtools') {
|
} else if (req.url === '/launch-chrome-devtools') {
|
||||||
if (isDebuggerConnected()) {
|
// TODO: Remove this case in the future
|
||||||
// Dev tools are already open; no need to open another session
|
console.log(
|
||||||
|
'The method /launch-chrome-devtools is deprecated. You are ' +
|
||||||
|
' probably using an application created with an older CLI with the ' +
|
||||||
|
' packager of a newer CLI. Please upgrade your application: ' +
|
||||||
|
'https://facebook.github.io/react-native/docs/upgrading.html');
|
||||||
|
launchDevTools(options, isChromeConnected);
|
||||||
res.end('OK');
|
res.end('OK');
|
||||||
return;
|
} else if (req.url === '/launch-js-devtools') {
|
||||||
}
|
launchDevTools(options, isChromeConnected);
|
||||||
var debuggerURL = 'http://localhost:' + options.port + '/debugger-ui';
|
|
||||||
console.log('Launching Dev Tools...');
|
|
||||||
opn(debuggerURL, {app: [getChromeAppName()]}, function(err) {
|
|
||||||
if (err) {
|
|
||||||
console.error('Google Chrome exited with error:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
res.end('OK');
|
res.end('OK');
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user