diff --git a/bin/next-dev b/bin/next-dev index e5f1a41cbf3e6..177923217b251 100755 --- a/bin/next-dev +++ b/bin/next-dev @@ -4,6 +4,7 @@ import parseArgs from 'minimist' import { exists } from 'mz/fs' import Server from '../server' import clean from '../server/build/clean' +import run from './util/run'; const argv = parseArgs(process.argv.slice(2), { alias: { @@ -21,8 +22,7 @@ const dir = resolve(argv._[0] || '.') clean(dir) .then(async () => { const srv = new Server({ dir, dev: true, hotReload: true }) - await srv.start(argv.port) - console.log('> Ready on http://localhost:%d', argv.port) + await run({ srv, port: argv.port }) // Check if pages dir exists and warn if not if (!(await exists(join(dir, 'pages')))) { diff --git a/bin/next-start b/bin/next-start index fbbe905977b86..2602354f0bac4 100755 --- a/bin/next-start +++ b/bin/next-start @@ -3,6 +3,7 @@ import { resolve } from 'path' import parseArgs from 'minimist' import Server from '../server' +import run from './util/run'; const argv = parseArgs(process.argv.slice(2), { alias: { @@ -18,10 +19,8 @@ const argv = parseArgs(process.argv.slice(2), { const dir = resolve(argv._[0] || '.') const srv = new Server({ dir }) -srv.start(argv.port) -.then(() => { - console.log('> Ready on http://localhost:%d', argv.port) -}) + +run({ srv, port: argv.port, shouldPrompt: false }) .catch((err) => { console.error(err) process.exit(1) diff --git a/bin/util/prompt.js b/bin/util/prompt.js new file mode 100644 index 0000000000000..08d46561b6739 --- /dev/null +++ b/bin/util/prompt.js @@ -0,0 +1,15 @@ +import rl from 'readline'; + +export default function (question) { + const rlInterface = rl.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + return new Promise((resolve) => { + rlInterface.question(question + '\n', function(answer) { + rlInterface.close(); + resolve(answer); + }); + }); +}; diff --git a/bin/util/run.js b/bin/util/run.js new file mode 100644 index 0000000000000..403a29df86049 --- /dev/null +++ b/bin/util/run.js @@ -0,0 +1,31 @@ +import prompt from './prompt'; +import detect from 'detect-port'; +import chalk from 'chalk'; + +const defaults = { shouldPrompt: true }; +export default async function run(opts) { + const { srv, port: desiredPort, shouldPrompt } = { ...defaults, ...opts }; + const port = await detect(desiredPort); + if (port !== desiredPort) { + if (!shouldPrompt) { + // Fail early if no prompt + console.error(`Error: Something is already running at port ${desiredPort}. Exiting.`); + process.exit(1); + } + + // Prompt the user to change the port. + let shouldChangePort = false; + if (shouldPrompt) { + const question = chalk.red(`Something is already running at port ${desiredPort}.\n` + + `Would you like to run the app on port ${port} instead? [Y/n]`); + const answer = await prompt(question); + shouldChangePort = !answer.length || answer.match(/^yes|y$/i); + } + if (!shouldChangePort) { + console.log(chalk.red('Exiting.')); + process.exit(0); + } + } + await srv.start(port); + console.log(`Ready on ${chalk.cyan(`http://localhost:${port}`)}`); +} diff --git a/gulpfile.js b/gulpfile.js index dc1fc29499aa0..f431e8a3305dc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -26,7 +26,7 @@ gulp.task('compile', [ ]) gulp.task('compile-bin', () => { - return gulp.src('bin/*') + return gulp.src(['bin/*', 'bin/**/*.js']) .pipe(cache('bin')) .pipe(babel(babelOptions)) .pipe(gulp.dest('dist/bin')) diff --git a/package.json b/package.json index 701c9fe2bad69..12c117da4ce97 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,10 @@ "babel-preset-es2015": "6.16.0", "babel-preset-react": "6.16.0", "babel-runtime": "6.11.6", + "chalk": "^1.1.3", "cross-spawn": "4.0.2", "del": "2.2.2", + "detect-port": "^1.0.1", "glamor": "2.17.10", "glob-promise": "1.0.6", "htmlescape": "1.1.1", @@ -59,6 +61,7 @@ "react": "15.3.2", "react-dom": "15.3.2", "react-hot-loader": "3.0.0-beta.6", + "readline": "^1.3.0", "send": "0.14.1", "strip-ansi": "3.0.1", "url": "0.11.0",