mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-05-16 19:09:05 +08:00
committed by
Dan Abramov
parent
a11d6a398f
commit
2edf2180f2
@@ -16,7 +16,7 @@ var paths = require('./paths');
|
||||
module.exports = {
|
||||
devtool: 'eval',
|
||||
entry: [
|
||||
require.resolve('webpack-dev-server/client') + '?http://localhost:3000',
|
||||
require.resolve('webpack-dev-server/client'),
|
||||
require.resolve('webpack/hot/dev-server'),
|
||||
require.resolve('./polyfills'),
|
||||
path.join(paths.appSrc, 'index')
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -9,27 +9,14 @@
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var rl = require('readline');
|
||||
var rimrafSync = require('rimraf').sync;
|
||||
var spawnSync = require('cross-spawn').sync;
|
||||
var paths = require('../config/paths');
|
||||
var prompt = require('./utils/prompt');
|
||||
|
||||
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' ||
|
||||
answer.toLowerCase() === 'yes'
|
||||
);
|
||||
prompt(
|
||||
'Are you sure you want to eject? This action is permanent.',
|
||||
false
|
||||
).then(shouldEject => {
|
||||
if (!shouldEject) {
|
||||
console.log('Close one! Eject aborted.');
|
||||
process.exit(1);
|
||||
@@ -52,7 +39,8 @@ prompt('Are you sure you want to eject? This action is permanent. [y/N]', functi
|
||||
path.join('config', 'webpack.config.prod.js'),
|
||||
path.join('scripts', 'build.js'),
|
||||
path.join('scripts', 'start.js'),
|
||||
path.join('scripts', 'openChrome.applescript')
|
||||
path.join('scripts', 'utils', 'chrome.applescript'),
|
||||
path.join('scripts', 'utils', 'prompt.js')
|
||||
];
|
||||
|
||||
// Ensure that the app folder is clean and we won't override any files
|
||||
@@ -72,6 +60,7 @@ prompt('Are you sure you want to eject? This action is permanent. [y/N]', functi
|
||||
fs.mkdirSync(path.join(appPath, 'config'));
|
||||
fs.mkdirSync(path.join(appPath, 'config', 'flow'));
|
||||
fs.mkdirSync(path.join(appPath, 'scripts'));
|
||||
fs.mkdirSync(path.join(appPath, 'scripts', 'utils'));
|
||||
|
||||
files.forEach(function(file) {
|
||||
console.log('Copying ' + file + ' to ' + appPath);
|
||||
|
||||
162
scripts/start.js
162
scripts/start.js
@@ -13,9 +13,14 @@ var path = require('path');
|
||||
var chalk = require('chalk');
|
||||
var webpack = require('webpack');
|
||||
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('./utils/prompt');
|
||||
var config = require('../config/webpack.config.dev');
|
||||
|
||||
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.
|
||||
@@ -63,63 +68,67 @@ 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) {
|
||||
compiler = webpack(config, handleCompile);
|
||||
|
||||
var json = stats.toJson();
|
||||
var formattedErrors = json.errors.map(message =>
|
||||
'Error in ' + formatMessage(message)
|
||||
);
|
||||
var formattedWarnings = json.warnings.map(message =>
|
||||
'Warning in ' + formatMessage(message)
|
||||
);
|
||||
compiler.plugin('invalid', function() {
|
||||
clearConsole();
|
||||
console.log('Compiling...');
|
||||
});
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
formattedErrors.forEach(message => {
|
||||
console.log(message);
|
||||
|
||||
var json = stats.toJson();
|
||||
var formattedErrors = json.errors.map(message =>
|
||||
'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 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();
|
||||
});
|
||||
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.');
|
||||
}
|
||||
});
|
||||
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
|
||||
@@ -127,8 +136,8 @@ function openBrowser() {
|
||||
execSync('ps cax | grep "Google Chrome"');
|
||||
execSync(
|
||||
'osascript ' +
|
||||
path.resolve(__dirname, './openChrome.applescript') +
|
||||
' http://localhost:3000/'
|
||||
path.resolve(__dirname, './utils/chrome.applescript') +
|
||||
' http://localhost:' + port + '/'
|
||||
);
|
||||
return;
|
||||
} catch (err) {
|
||||
@@ -137,21 +146,46 @@ 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 => {
|
||||
if (port === DEFAULT_PORT) {
|
||||
run(port);
|
||||
return;
|
||||
}
|
||||
|
||||
clearConsole();
|
||||
console.log(chalk.cyan('Starting the development server...'));
|
||||
console.log();
|
||||
openBrowser();
|
||||
var question =
|
||||
chalk.yellow('Something is already running at port ' + DEFAULT_PORT + '.') +
|
||||
'\n\nWould you like to run the app at another port instead?';
|
||||
|
||||
prompt(question, true).then(shouldChangePort => {
|
||||
if (shouldChangePort) {
|
||||
run(port);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
40
scripts/utils/prompt.js
Normal file
40
scripts/utils/prompt.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
var rl = require('readline');
|
||||
|
||||
// Convention: "no" should be the conservative choice.
|
||||
// If you mistype the answer, we'll always take it as a "no".
|
||||
// You can control the behavior on <Enter> with `isYesDefault`.
|
||||
module.exports = function (question, isYesDefault) {
|
||||
if (typeof isYesDefault !== 'boolean') {
|
||||
throw new Error('Provide explicit boolean isYesDefault as second argument.');
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
var rlInterface = rl.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
var hint = isYesDefault === true ? '[Y/n]' : '[y/N]';
|
||||
var message = question + ' ' + hint + '\n';
|
||||
|
||||
rlInterface.question(message, function(answer) {
|
||||
rlInterface.close();
|
||||
|
||||
var useDefault = answer.trim().length === 0;
|
||||
if (useDefault) {
|
||||
return resolve(isYesDefault);
|
||||
}
|
||||
|
||||
var isYes = answer.match(/^(yes|y)$/i);
|
||||
return resolve(isYes);
|
||||
});
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user