@@ -13,9 +13,14 @@ var path = require('path');
1313var chalk = require ( 'chalk' ) ;
1414var webpack = require ( 'webpack' ) ;
1515var WebpackDevServer = require ( 'webpack-dev-server' ) ;
16- var config = require ( '../config/webpack.config.dev' ) ;
1716var execSync = require ( 'child_process' ) . execSync ;
1817var opn = require ( 'opn' ) ;
18+ var detect = require ( 'detect-port' ) ;
19+ var prompt = require ( './utils/prompt' ) ;
20+ var config = require ( '../config/webpack.config.dev' ) ;
21+
22+ var DEFAULT_PORT = 3000 ;
23+ var compiler ;
1924
2025// TODO: hide this behind a flag and eliminate dead code on eject.
2126// This shouldn't be exposed to the user.
@@ -63,72 +68,76 @@ function clearConsole() {
6368 process . stdout . write ( '\x1B[2J\x1B[0f' ) ;
6469}
6570
66- var compiler = webpack ( config , handleCompile ) ;
67- compiler . plugin ( 'invalid' , function ( ) {
68- clearConsole ( ) ;
69- console . log ( 'Compiling...' ) ;
70- } ) ;
71- compiler . plugin ( 'done' , function ( stats ) {
72- clearConsole ( ) ;
73- var hasErrors = stats . hasErrors ( ) ;
74- var hasWarnings = stats . hasWarnings ( ) ;
75- if ( ! hasErrors && ! hasWarnings ) {
76- console . log ( chalk . green ( 'Compiled successfully!' ) ) ;
77- console . log ( ) ;
78- console . log ( 'The app is running at http://localhost:3000/' ) ;
79- console . log ( ) ;
80- return ;
81- }
71+ function setupCompiler ( port ) {
72+ compiler = webpack ( config , handleCompile ) ;
8273
83- var json = stats . toJson ( ) ;
84- var formattedErrors = json . errors . map ( message =>
85- 'Error in ' + formatMessage ( message )
86- ) ;
87- var formattedWarnings = json . warnings . map ( message =>
88- 'Warning in ' + formatMessage ( message )
89- ) ;
74+ compiler . plugin ( 'invalid' , function ( ) {
75+ clearConsole ( ) ;
76+ console . log ( 'Compiling...' ) ;
77+ } ) ;
9078
91- if ( hasErrors ) {
92- console . log ( chalk . red ( 'Failed to compile.' ) ) ;
93- console . log ( ) ;
94- if ( formattedErrors . some ( isLikelyASyntaxError ) ) {
95- // If there are any syntax errors, show just them.
96- // This prevents a confusing ESLint parsing error
97- // preceding a much more useful Babel syntax error.
98- formattedErrors = formattedErrors . filter ( isLikelyASyntaxError ) ;
99- }
100- formattedErrors . forEach ( message => {
101- console . log ( message ) ;
79+ compiler . plugin ( 'done' , function ( stats ) {
80+ clearConsole ( ) ;
81+ var hasErrors = stats . hasErrors ( ) ;
82+ var hasWarnings = stats . hasWarnings ( ) ;
83+ if ( ! hasErrors && ! hasWarnings ) {
84+ console . log ( chalk . green ( 'Compiled successfully!' ) ) ;
10285 console . log ( ) ;
103- } ) ;
104- // If errors exist, ignore warnings.
105- return ;
106- }
86+ console . log ( 'The app is running at http://localhost:' + port + '/' ) ;
87+ console . log ( ) ;
88+ return ;
89+ }
10790
108- if ( hasWarnings ) {
109- console . log ( chalk . yellow ( 'Compiled with warnings.' ) ) ;
110- console . log ( ) ;
111- formattedWarnings . forEach ( message => {
112- console . log ( message ) ;
91+ var json = stats . toJson ( ) ;
92+ var formattedErrors = json . errors . map ( message =>
93+ 'Error in ' + formatMessage ( message )
94+ ) ;
95+ var formattedWarnings = json . warnings . map ( message =>
96+ 'Warning in ' + formatMessage ( message )
97+ ) ;
98+
99+ if ( hasErrors ) {
100+ console . log ( chalk . red ( 'Failed to compile.' ) ) ;
113101 console . log ( ) ;
114- } ) ;
102+ if ( formattedErrors . some ( isLikelyASyntaxError ) ) {
103+ // If there are any syntax errors, show just them.
104+ // This prevents a confusing ESLint parsing error
105+ // preceding a much more useful Babel syntax error.
106+ formattedErrors = formattedErrors . filter ( isLikelyASyntaxError ) ;
107+ }
108+ formattedErrors . forEach ( message => {
109+ console . log ( message ) ;
110+ console . log ( ) ;
111+ } ) ;
112+ // If errors exist, ignore warnings.
113+ return ;
114+ }
115115
116- console . log ( 'You may use special comments to disable some warnings.' ) ;
117- console . log ( 'Use ' + chalk . yellow ( '// eslint-disable-next-line' ) + ' to ignore the next line.' ) ;
118- console . log ( 'Use ' + chalk . yellow ( '/* eslint-disable */' ) + ' to ignore all warnings in a file.' ) ;
119- }
120- } ) ;
116+ if ( hasWarnings ) {
117+ console . log ( chalk . yellow ( 'Compiled with warnings.' ) ) ;
118+ console . log ( ) ;
119+ formattedWarnings . forEach ( message => {
120+ console . log ( message ) ;
121+ console . log ( ) ;
122+ } ) ;
123+
124+ console . log ( 'You may use special comments to disable some warnings.' ) ;
125+ console . log ( 'Use ' + chalk . yellow ( '// eslint-disable-next-line' ) + ' to ignore the next line.' ) ;
126+ console . log ( 'Use ' + chalk . yellow ( '/* eslint-disable */' ) + ' to ignore all warnings in a file.' ) ;
127+ }
128+ } ) ;
129+ }
121130
122- function openBrowser ( ) {
131+ function openBrowser ( port ) {
123132 if ( process . platform === 'darwin' ) {
124133 try {
125134 // Try our best to reuse existing tab
126135 // on OS X Google Chrome with AppleScript
127136 execSync ( 'ps cax | grep "Google Chrome"' ) ;
128137 execSync (
129138 'osascript ' +
130- path . resolve ( __dirname , './openChrome .applescript' ) +
131- ' http://localhost:3000 /'
139+ path . resolve ( __dirname , './utils/chrome .applescript' ) +
140+ ' http://localhost:' + port + ' /'
132141 ) ;
133142 return ;
134143 } catch ( err ) {
@@ -137,21 +146,46 @@ function openBrowser() {
137146 }
138147 // Fallback to opn
139148 // (It will always open new tab)
140- opn ( 'http://localhost:3000/' ) ;
149+ opn ( 'http://localhost:' + port + '/' ) ;
150+ }
151+
152+ function runDevServer ( port ) {
153+ new WebpackDevServer ( compiler , {
154+ historyApiFallback : true ,
155+ hot : true , // Note: only CSS is currently hot reloaded
156+ publicPath : config . output . publicPath ,
157+ quiet : true
158+ } ) . listen ( port , ( err , result ) => {
159+ if ( err ) {
160+ return console . log ( err ) ;
161+ }
162+
163+ clearConsole ( ) ;
164+ console . log ( chalk . cyan ( 'Starting the development server...' ) ) ;
165+ console . log ( ) ;
166+ openBrowser ( port ) ;
167+ } ) ;
141168}
142169
143- new WebpackDevServer ( compiler , {
144- historyApiFallback : true ,
145- hot : true , // Note: only CSS is currently hot reloaded
146- publicPath : config . output . publicPath ,
147- quiet : true
148- } ) . listen ( 3000 , function ( err , result ) {
149- if ( err ) {
150- return console . log ( err ) ;
170+ function run ( port ) {
171+ setupCompiler ( port ) ;
172+ runDevServer ( port ) ;
173+ }
174+
175+ detect ( DEFAULT_PORT ) . then ( port => {
176+ if ( port === DEFAULT_PORT ) {
177+ run ( port ) ;
178+ return ;
151179 }
152180
153181 clearConsole ( ) ;
154- console . log ( chalk . cyan ( 'Starting the development server...' ) ) ;
155- console . log ( ) ;
156- openBrowser ( ) ;
182+ var question =
183+ chalk . yellow ( 'Something is already running at port ' + DEFAULT_PORT + '.' ) +
184+ '\n\nWould you like to run the app at another port instead?' ;
185+
186+ prompt ( question , true ) . then ( shouldChangePort => {
187+ if ( shouldChangePort ) {
188+ run ( port ) ;
189+ }
190+ } ) ;
157191} ) ;
0 commit comments