Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interactive mode with keyboard commands #326

Merged
merged 11 commits into from
Jul 28, 2017
2 changes: 0 additions & 2 deletions react-native-scripts/src/scripts/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ Config.validation.reactNativeVersionWarnings = false;
Config.developerTool = 'crna';
Config.offline = true;

const command: string = pathExists.sync(path.join(process.cwd(), 'yarn.lock')) ? 'yarnpkg' : 'npm';

packager.run(startAndroidAndPrintInfo);

// print a nicely formatted message with setup information
Expand Down
97 changes: 91 additions & 6 deletions react-native-scripts/src/scripts/start.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
// @flow

import { Config, ProjectSettings, UrlUtils } from 'xdl';
import { Android, Config, Project, ProjectSettings, Simulator, UrlUtils } from 'xdl';

import chalk from 'chalk';
import indent from 'indent-string';
import qr from 'qrcode-terminal';
import minimist from 'minimist';
import log from '../util/log';
import clearConsole from '../util/clearConsole';

import packager from '../util/packager';

Config.validation.reactNativeVersionWarnings = false;
Config.developerTool = 'crna';
Config.offline = true;

const args = require('minimist')(process.argv.slice(2), { boolean: ['--reset-cache'] });
const args = minimist(process.argv.slice(2), { boolean: ['--reset-cache'] });

let dev = true;

const options = {};
if (args['reset-cache']) {
options.reset = true;
log('Asking packager to reset its cache...');
}

packager.run(printServerInfo, options);
const { stdin } = process;
if (typeof stdin.setRawMode === 'function') {
stdin.setRawMode(true);
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', handleKeypress);
}

packager.run(onReady, options);

function onReady() {
log(chalk.green('Packager started!\n'));
printServerInfo();
}

// print a nicely formatted message with setup information
async function printServerInfo() {
Expand All @@ -30,9 +47,7 @@ async function printServerInfo() {
const address = await UrlUtils.constructManifestUrlAsync(process.cwd());
qr.generate(address, qrCode => {
log(
`${chalk.green('Packager started!')}

To view your app with live reloading, point the Expo app to this QR code.
`To view your app with live reloading, point the Expo app to this QR code.
You'll find the QR scanner on the Projects tab of the app.

${indent(qrCode, 2)}
Expand All @@ -48,5 +63,75 @@ For links to install the Expo app, please visit ${chalk.underline(chalk.cyan('ht
Logs from serving your app will appear here. Press Ctrl+C at any time to stop.
`
);
printUsage();
});
}

function printUsage() {
const devMode = chalk.bold(dev ? 'development' : 'production');
log(
`${chalk.bold('Usage')}
${chalk.dim('\u203A Press')} a ${chalk.dim('to open Android device or emulator.')}
${chalk.dim('\u203A Press')} i ${chalk.dim('to open iOS emulator.')}
${chalk.dim('\u203A Press')} q ${chalk.dim('to display QR code.')}
${chalk.dim('\u203A Press')} r ${chalk.dim('to restart packager.')}
${chalk.dim('\u203A Press')} R ${chalk.dim('to restart packager and clear cache.')}
${chalk.dim('\u203A Press')} d ${chalk.dim('to toggle development mode. (current mode: ' + devMode)})`
);
}

const CTRL_C = '\u0003';
const CTRL_D = '\u0004';

async function handleKeypress(key) {
switch (key) {
case CTRL_C:
case CTRL_D:
process.exit();
case 'a': {
clearConsole();
log.withTimestamp('Starting Android...');
const { success, error } = await Android.openProjectAsync(process.cwd());
if (!success) {
log(chalk.red(error.message));
}
printUsage();
return;
}
case 'i': {
clearConsole();
log.withTimestamp('Starting iOS...');
const localAddress = await UrlUtils.constructManifestUrlAsync(process.cwd(), {
hostType: 'localhost',
});
const { success, msg } = await Simulator.openUrlInSimulatorSafeAsync(localAddress);
if (!success) {
log(chalk.red(msg));
}
printUsage();
return;
}
case 'q':
clearConsole();
await printServerInfo();
return;
case 'r':
case 'R': {
clearConsole();
const reset = key === 'R';
if (reset) {
log.withTimestamp('Asking packager to reset its cache...');
}
log.withTimestamp('Restarting packager...');
Project.startAsync(process.cwd(), { reset });
return;
}
case 'd':
clearConsole();
dev = !dev;
await ProjectSettings.setAsync(process.cwd(), { dev });
log(`Packager now running in ${chalk.bold(dev ? 'development' : 'production')} mode.`);
printUsage();
return;
}
}
3 changes: 3 additions & 0 deletions react-native-scripts/src/util/clearConsole.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function clearConsole() {
process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H');
}
5 changes: 0 additions & 5 deletions react-native-scripts/src/util/packager.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ import chalk from 'chalk';

import log from './log';

// TODO get babel output that's nice enough to let it take over the console
function clearConsole() {
process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H');
}

function installExitHooks(projectDir) {
if (process.platform === 'win32') {
require('readline')
Expand Down