@@ -13,9 +13,14 @@ var path = require('path');
13
13
var chalk = require ( 'chalk' ) ;
14
14
var webpack = require ( 'webpack' ) ;
15
15
var WebpackDevServer = require ( 'webpack-dev-server' ) ;
16
- var config = require ( '../config/webpack.config.dev' ) ;
17
16
var execSync = require ( 'child_process' ) . execSync ;
18
17
var 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 ;
19
24
20
25
// TODO: hide this behind a flag and eliminate dead code on eject.
21
26
// This shouldn't be exposed to the user.
@@ -63,72 +68,76 @@ function clearConsole() {
63
68
process . stdout . write ( '\x1B[2J\x1B[0f' ) ;
64
69
}
65
70
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 ) ;
82
73
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
+ } ) ;
90
78
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!' ) ) ;
102
85
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
+ }
107
90
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.' ) ) ;
113
101
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
+ }
115
115
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
+ }
121
130
122
- function openBrowser ( ) {
131
+ function openBrowser ( port ) {
123
132
if ( process . platform === 'darwin' ) {
124
133
try {
125
134
// Try our best to reuse existing tab
126
135
// on OS X Google Chrome with AppleScript
127
136
execSync ( 'ps cax | grep "Google Chrome"' ) ;
128
137
execSync (
129
138
'osascript ' +
130
- path . resolve ( __dirname , './openChrome .applescript' ) +
131
- ' http://localhost:3000 /'
139
+ path . resolve ( __dirname , './utils/chrome .applescript' ) +
140
+ ' http://localhost:' + port + ' /'
132
141
) ;
133
142
return ;
134
143
} catch ( err ) {
@@ -137,21 +146,46 @@ function openBrowser() {
137
146
}
138
147
// Fallback to opn
139
148
// (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
+ } ) ;
141
168
}
142
169
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 ;
151
179
}
152
180
153
181
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
+ } ) ;
157
191
} ) ;
0 commit comments