Permalink
Browse files

adds --port option to `react-native run-ios` as well as patches port …

Summary:
The pull request adds the `--port` option to `run-ios` allowing a developer to build and launch a react-native app using a single command line like this:
```
react-native run-ios --port 8088
```

It defaults to the current port 8081.

This pull request fixes issue #9145 and issue #14113.

This patch also extends `run-android` to properly test and launch the packager with the specified port, extending the work done in PR:  ##15316

1. Create a new react-native app, or simply clone this branch and then update your version of react-native using `yarn add file:./path/to/this/fork/of/react-native`
2. run `react-native run-ios --port 8088`
3. watch the packager start on the desired port (8088 in this case) and watch your app in your simulator connect to the packager and launch the app.
Closes #16172

Differential Revision: D6612534

Pulled By: shergin

fbshipit-source-id: 50af449f5e4c32fb76ba95f4cb7bf179e35526d5
  • Loading branch information...
Michael S. Kazmier authored and facebook-github-bot committed Jan 5, 2018
1 parent e57a43b commit 33d710e8c58ef1dc69816a59ac1cf390894e7cb9
@@ -433,6 +433,11 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"RCT_METRO_PORT=${RCT_METRO_PORT}",
"$(inherited)",
);
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -443,6 +448,7 @@
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = "RCT_METRO_PORT=${RCT_METRO_PORT}";
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -54,7 +54,7 @@ - (instancetype)initWithURL:(NSURL *)URL
- (void)setUp
{
if (!_url) {
NSInteger port = [[[_bridge bundleURL] port] integerValue] ?: 8081;
NSInteger port = [[[_bridge bundleURL] port] integerValue] ?: RCT_METRO_PORT;
NSString *host = [[_bridge bundleURL] host] ?: @"localhost";
NSString *URLString = [NSString stringWithFormat:@"http://%@:%lld/debugger-proxy?role=client", host, (long long)port];
_url = [RCTConvert NSURL:URLString];
@@ -14,7 +14,7 @@

NSString *const RCTBundleURLProviderUpdatedNotification = @"RCTBundleURLProviderUpdatedNotification";

const NSUInteger kRCTBundleURLProviderDefaultPort = 8081;
const NSUInteger kRCTBundleURLProviderDefaultPort = RCT_METRO_PORT;

static NSString *const kRCTJsLocationKey = @"RCT_jsLocation";
static NSString *const kRCTEnableLiveReloadKey = @"RCT_enableLiveReload";
@@ -74,6 +74,23 @@
#define RCT_PROFILE RCT_DEV
#endif

/**
* Add the default Metro packager port number
*/
#ifndef RCT_METRO_PORT
#define RCT_METRO_PORT 8081
#else
// test if RCT_METRO_PORT is empty
#define RCT_METRO_PORT_DO_EXPAND(VAL) VAL ## 1
#define RCT_METRO_PORT_EXPAND(VAL) RCT_METRO_PORT_DO_EXPAND(VAL)
#if !defined(RCT_METRO_PORT) || (RCT_METRO_PORT_EXPAND(RCT_METRO_PORT) == 1)
// Only here if RCT_METRO_PORT is not defined
// OR RCT_METRO_PORT is the empty string
#undef RCT_METRO_PORT
#define RCT_METRO_PORT 8081
#endif
#endif

/**
* By default, only raise an NSAssertion in debug mode
* (custom assert functions will still be called).
@@ -3957,7 +3957,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi";
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi";
showEnvVarsInLog = 0;
};
142C4F7F1B582EA6001F0B58 /* Include RCTJSCProfiler */ = {
@@ -5100,6 +5100,13 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_STATIC_ANALYZER_MODE = deep;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"RCT_DEBUG=1",
"RCT_DEV=1",
"RCT_NSASSERT=1",
"RCT_METRO_PORT=${RCT_METRO_PORT}",
);
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5114,7 +5121,10 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_STATIC_ANALYZER_MODE = deep;
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"RCT_METRO_PORT=${RCT_METRO_PORT}",
);
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -45,15 +45,15 @@ function runAndroid(argv, config, args) {
return buildAndRun(args);
}

return isPackagerRunning().then(result => {
return isPackagerRunning(args.port).then(result => {
if (result === 'running') {
console.log(chalk.bold('JS server already running.'));
} else if (result === 'unrecognized') {
console.warn(chalk.yellow('JS server not recognized, continuing with build...'));
} else {
// result == 'not_running'
console.log(chalk.bold('Starting JS server...'));
startServerInNewWindow();
startServerInNewWindow(args.port);
}
return buildAndRun(args);
});
@@ -262,7 +262,7 @@ function runOnAllDevices(args, cmd, packageNameWithSuffix, packageName, adbPath)
}
}

function startServerInNewWindow() {
function startServerInNewWindow(port) {
const scriptFile = /^win/.test(process.platform) ?
'launchPackager.bat' :
'launchPackager.command';
@@ -271,6 +271,12 @@ function startServerInNewWindow() {
const procConfig = {cwd: scriptsDir};
const terminal = process.env.REACT_TERMINAL;

// setup the .packager.env file to ensure the packager starts on the right port
const packagerEnvFile = path.join(__dirname, '..', '..', 'scripts', '.packager.env');
const content = `export RCT_METRO_PORT=${port}`;
// ensure we overwrite file by passing the 'w' flag
fs.writeFileSync(packagerEnvFile, content, {encoding: 'utf8', flag: 'w'});

if (process.platform === 'darwin') {
if (terminal) {
return child_process.spawnSync('open', ['-a', terminal, launchPackagerScript], procConfig);
@@ -333,7 +339,7 @@ module.exports = {
description: 'Do not launch packager while building',
}, {
command: '--port [number]',
default: 8081,
default: process.env.RCT_METRO_PORT || 8081,
parse: (val: string) => Number(val),
}],
};
@@ -78,7 +78,7 @@ function runIOS(argv, config, args) {
function runOnDeviceByUdid(args, scheme, xcodeProject, devices) {
const selectedDevice = matchingDeviceByUdid(devices, args.udid);
if (selectedDevice) {
return runOnDevice(selectedDevice, scheme, xcodeProject, args.configuration, args.packager, args.verbose);
return runOnDevice(selectedDevice, scheme, xcodeProject, args.configuration, args.packager, args.verbose, args.port);
} else {
if (devices && devices.length > 0) {
console.log('Could not find device with the udid: "' + args.udid + '".');
@@ -115,7 +115,7 @@ function runOnSimulator(xcodeProject, args, scheme) {
}
resolve(selectedSimulator.udid);
})
.then((udid) => buildProject(xcodeProject, udid, scheme, args.configuration, args.packager, args.verbose))
.then((udid) => buildProject(xcodeProject, udid, scheme, args.configuration, args.packager, args.verbose, args.port))
.then((appName) => {
if (!appName) {
appName = scheme;
@@ -135,8 +135,8 @@ function runOnSimulator(xcodeProject, args, scheme) {
});
}

function runOnDevice(selectedDevice, scheme, xcodeProject, configuration, launchPackager, verbose) {
return buildProject(xcodeProject, selectedDevice.udid, scheme, configuration, launchPackager, verbose)
function runOnDevice(selectedDevice, scheme, xcodeProject, configuration, launchPackager, verbose, port) {
return buildProject(xcodeProject, selectedDevice.udid, scheme, configuration, launchPackager, verbose, port)
.then((appName) => {
if (!appName) {
appName = scheme;
@@ -159,7 +159,7 @@ function runOnDevice(selectedDevice, scheme, xcodeProject, configuration, launch
});
}

function buildProject(xcodeProject, udid, scheme, configuration = 'Debug', launchPackager = false, verbose) {
function buildProject(xcodeProject, udid, scheme, configuration = 'Debug', launchPackager = false, verbose, port) {
return new Promise((resolve,reject) =>
{
var xcodebuildArgs = [
@@ -174,7 +174,7 @@ function buildProject(xcodeProject, udid, scheme, configuration = 'Debug', launc
if (!verbose) {
xcpretty = xcprettyAvailable() && child_process.spawn('xcpretty', [], { stdio: ['pipe', process.stdout, process.stderr] });
}
const buildProcess = child_process.spawn('xcodebuild', xcodebuildArgs, getProcessOptions(launchPackager));
const buildProcess = child_process.spawn('xcodebuild', xcodebuildArgs, getProcessOptions(launchPackager, port));
let buildOutput = '';
buildProcess.stdout.on('data', function(data) {
buildOutput += data.toString();
@@ -232,13 +232,15 @@ function printFoundDevices(devices) {
}
}

function getProcessOptions(launchPackager) {
function getProcessOptions(launchPackager, port) {
if (launchPackager) {
return {};
return {
env: { ...process.env, RCT_METRO_PORT: port }
};
}

return {
env: Object.assign({}, process.env, { RCT_NO_LAUNCH_PACKAGER: true }),
env: { ...process.env, RCT_NO_LAUNCH_PACKAGER: true },
};
}

@@ -287,5 +289,9 @@ module.exports = {
}, {
command: '--verbose',
description: 'Do not use xcpretty even if installed',
},{
command: '--port [number]',
default: process.env.RCT_METRO_PORT || 8081,
parse: (val: string) => Number(val),
}],
};
@@ -60,7 +60,7 @@ module.exports = {
description: 'starts the webserver',
options: [{
command: '--port [number]',
default: 8081,
default: process.env.RCT_METRO_PORT || 8081,
parse: (val: string) => Number(val),
}, {
command: '--host [string]',
@@ -19,8 +19,8 @@ const fetch = require('node-fetch');
* - `unrecognized`: one other process is running on the port we expect the
* packager to be running.
*/
function isPackagerRunning() {
return fetch('http://localhost:8081/status').then(
function isPackagerRunning(packagerPort = (process.env.RCT_METRO_PORT || 8081)) {
return fetch(`http://localhost:${packagerPort}/status`).then(
res => res.text().then(body =>
body === 'packager-status:running' ? 'running' : 'unrecognized'
),
@@ -8,5 +8,6 @@
# of patent rights can be found in the PATENTS file in the same directory.

THIS_DIR=$(dirname "$0")
source "${THIS_DIR}/.packager.env"
cd "$THIS_DIR/.."
node "./local-cli/cli.js" start "$@"

1 comment on commit 33d710e

@berkcoker

This comment has been minimized.

Copy link

berkcoker commented on 33d710e Feb 8, 2018

This commit causes react native to fail on --device option... Port is set to undefined no matter what is specified through the option

Please sign in to comment.