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

WIP prompt if port is already in use. #101

Closed
wants to merge 14 commits into from
Closed
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -41,6 +41,7 @@
"chalk": "1.1.3",
"cross-spawn": "4.0.0",
"css-loader": "0.23.1",
"detect-port": "^0.1.4",
"eslint": "3.1.1",
"eslint-loader": "1.4.1",
"eslint-plugin-import": "1.10.3",
Expand Down
13 changes: 1 addition & 12 deletions scripts/eject.js
Expand Up @@ -9,22 +9,11 @@

var fs = require('fs');
var path = require('path');
var rl = require('readline');
var rimrafSync = require('rimraf').sync;
var spawnSync = require('cross-spawn').sync;
var prompt = require('./utilities/prompt');
var paths = require('../config/paths');

var prompt = function(question, cb) {
var rlInterface = rl.createInterface({
input: process.stdin,
output: process.stdout,
});
rlInterface.question(question + '\n', function(answer) {
rlInterface.close();
cb(answer);
})
}

prompt('Are you sure you want to eject? This action is permanent. [y/N]', function(answer) {
var shouldEject = answer && (
answer.toLowerCase() === 'y' ||
Expand Down
170 changes: 104 additions & 66 deletions scripts/start.js
Expand Up @@ -16,6 +16,10 @@ var WebpackDevServer = require('webpack-dev-server');
var config = require('../config/webpack.config.dev');
var execSync = require('child_process').execSync;
var opn = require('opn');
var detect = require('detect-port');
var prompt = require('./utilities/prompt');
var DEFAULT_PORT = 3000;
var compiler;

// TODO: hide this behind a flag and eliminate dead code on eject.
// This shouldn't be exposed to the user.
Expand Down Expand Up @@ -63,63 +67,70 @@ function clearConsole() {
process.stdout.write('\x1B[2J\x1B[0f');
}

var compiler = webpack(config, handleCompile);
compiler.plugin('invalid', function () {
clearConsole();
console.log('Compiling...');
});
compiler.plugin('done', function (stats) {
clearConsole();
var hasErrors = stats.hasErrors();
var hasWarnings = stats.hasWarnings();
if (!hasErrors && !hasWarnings) {
console.log(chalk.green('Compiled successfully!'));
console.log();
console.log('The app is running at http://localhost:3000/');
console.log();
return;
}
function setupCompiler(port) {
var copyConfig = Object.assign({}, config, {
entry: config.entry.map(c => c.replace(/(\d+)/g, port))
});

compiler = webpack(copyConfig, handleCompile);
compiler.plugin('invalid', function() {
clearConsole();
console.log('Compiling...');
});

compiler.plugin('done', function(stats) {
clearConsole();
var hasErrors = stats.hasErrors();
var hasWarnings = stats.hasWarnings();
if (!hasErrors && !hasWarnings) {
console.log(chalk.green('Compiled successfully!'));
console.log();
console.log('The app is running at http://localhost:' + port + '/');
console.log();
return;
}

var json = stats.toJson();
var formattedErrors = json.errors.map(message =>
'Error in ' + formatMessage(message)
);
var formattedWarnings = json.warnings.map(message =>
'Warning in ' + formatMessage(message)
);
var json = stats.toJson();
var formattedErrors = json.errors.map(message =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we're using arrow functions and standard functions in the same file? I don't mind either syntax but I think consistency is a good idea. That is, unless we need the syntax difference for the different ways they handle things, but if it's just arbitrary I'd prefer we just stuck with one :)

'Error in ' + formatMessage(message)
);
var formattedWarnings = json.warnings.map(message =>
'Warning in ' + formatMessage(message)
);

if (hasErrors) {
console.log(chalk.red('Failed to compile.'));
console.log();
if (formattedErrors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
// This prevents a confusing ESLint parsing error
// preceding a much more useful Babel syntax error.
formattedErrors = formattedErrors.filter(isLikelyASyntaxError);
}
formattedErrors.forEach(message => {
console.log(message);
if (hasErrors) {
console.log(chalk.red('Failed to compile.'));
console.log();
});
// If errors exist, ignore warnings.
return;
}
if (formattedErrors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
// This prevents a confusing ESLint parsing error
// preceding a much more useful Babel syntax error.
formattedErrors = formattedErrors.filter(isLikelyASyntaxError);
}
formattedErrors.forEach(message => {
console.log(message);
console.log();
});
// If errors exist, ignore warnings.
return;
}

if (hasWarnings) {
console.log(chalk.yellow('Compiled with warnings.'));
console.log();
formattedWarnings.forEach(message => {
console.log(message);
if (hasWarnings) {
console.log(chalk.yellow('Compiled with warnings.'));
console.log();
});

console.log('You may use special comments to disable some warnings.');
console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
}
});
formattedWarnings.forEach(message => {
console.log(message);
console.log();
});

console.log('You may use special comments to disable some warnings.');
console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.');
console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.');
}
});
}

function openBrowser() {
function openBrowser(port) {
if (process.platform === 'darwin') {
try {
// Try our best to reuse existing tab
Expand All @@ -128,7 +139,7 @@ function openBrowser() {
execSync(
'osascript ' +
path.resolve(__dirname, './openChrome.applescript') +
' http://localhost:3000/'
' http://localhost:' + port + '/'
);
return;
} catch (err) {
Expand All @@ -137,21 +148,48 @@ function openBrowser() {
}
// Fallback to opn
// (It will always open new tab)
opn('http://localhost:3000/');
opn('http://localhost:' + port + '/');
}

new WebpackDevServer(compiler, {
historyApiFallback: true,
hot: true, // Note: only CSS is currently hot reloaded
publicPath: config.output.publicPath,
quiet: true
}).listen(3000, function (err, result) {
if (err) {
return console.log(err);
}
function runDevServer(port) {
new WebpackDevServer(compiler, {
historyApiFallback: true,
hot: true, // Note: only CSS is currently hot reloaded
publicPath: config.output.publicPath,
quiet: true
}).listen(port, (err, result) => {
if (err) {
return console.log(err);
}

clearConsole();
console.log(chalk.cyan('Starting the development server...'));
console.log();
openBrowser(port);
});
}

function run(port) {
setupCompiler(port);
runDevServer(port);
}

detect(DEFAULT_PORT).then(port => {

clearConsole();
console.log(chalk.cyan('Starting the development server...'));
console.log();
openBrowser();
if (port !== DEFAULT_PORT) {
var question = chalk.red('Something is already running at port ' + DEFAULT_PORT) +
'\nWould you like to run the app at another port instead? [y/N]';

prompt(question, answer => {
var shouldChangePort = (
answer.length === 0 ||
answer.match(/^yes|y$/i)
);
if (shouldChangePort) {
run(port);
}
});
} else {
run(port);
}
});
13 changes: 13 additions & 0 deletions scripts/utilities/prompt.js
@@ -0,0 +1,13 @@
var rl = require('readline');

module.exports = function (question, cb) {
var rlInterface = rl.createInterface({
input: process.stdin,
output: process.stdout,
});

rlInterface.question(question + '\n', function(answer) {
rlInterface.close();
cb(answer);
});
};