@@ -17,21 +17,20 @@ process.env.NODE_ENV = 'development';
17
17
// https://github.com/motdotla/dotenv
18
18
require ( 'dotenv' ) . config ( { silent : true } ) ;
19
19
20
+ var fs = require ( 'fs' ) ;
20
21
var chalk = require ( 'chalk' ) ;
21
- var webpack = require ( 'webpack' ) ;
22
- var WebpackDevServer = require ( 'webpack-dev-server' ) ;
23
- var historyApiFallback = require ( 'connect-history-api-fallback' ) ;
24
- var httpProxyMiddleware = require ( 'http-proxy-middleware' ) ;
25
22
var detect = require ( 'detect-port' ) ;
23
+ var WebpackDevServer = require ( 'webpack-dev-server' ) ;
26
24
var clearConsole = require ( 'react-dev-utils/clearConsole' ) ;
27
25
var checkRequiredFiles = require ( 'react-dev-utils/checkRequiredFiles' ) ;
28
- var formatWebpackMessages = require ( 'react-dev-utils/formatWebpackMessages' ) ;
29
26
var getProcessForPort = require ( 'react-dev-utils/getProcessForPort' ) ;
30
27
var openBrowser = require ( 'react-dev-utils/openBrowser' ) ;
31
28
var prompt = require ( 'react-dev-utils/prompt' ) ;
32
- var fs = require ( 'fs' ) ;
33
- var config = require ( '../config/webpack.config.dev' ) ;
34
29
var paths = require ( '../config/paths' ) ;
30
+ var config = require ( '../config/webpack.config.dev' ) ;
31
+ var devServerConfig = require ( '../config/webpackDevServer.config' ) ;
32
+ var createWebpackCompiler = require ( './utils/createWebpackCompiler' ) ;
33
+ var addWebpackMiddleware = require ( './utils/addWebpackMiddleware' ) ;
35
34
36
35
var useYarn = fs . existsSync ( paths . yarnLockFile ) ;
37
36
var cli = useYarn ? 'yarn' : 'npm' ;
@@ -44,247 +43,31 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
44
43
45
44
// Tools like Cloud9 rely on this.
46
45
var DEFAULT_PORT = parseInt ( process . env . PORT , 10 ) || 3000 ;
47
- var compiler ;
48
- var handleCompile ;
49
-
50
- // You can safely remove this after ejecting.
51
- // We only use this block for testing of Create React App itself:
52
- var isSmokeTest = process . argv . some ( arg => arg . indexOf ( '--smoke-test' ) > - 1 ) ;
53
- if ( isSmokeTest ) {
54
- handleCompile = function ( err , stats ) {
55
- if ( err || stats . hasErrors ( ) || stats . hasWarnings ( ) ) {
56
- process . exit ( 1 ) ;
57
- } else {
58
- process . exit ( 0 ) ;
59
- }
60
- } ;
61
- }
62
-
63
- function setupCompiler ( host , port , protocol ) {
64
- // "Compiler" is a low-level interface to Webpack.
65
- // It lets us listen to some events and provide our own custom messages.
66
- try {
67
- compiler = webpack ( config , handleCompile ) ;
68
- } catch ( err ) {
69
- console . log ( chalk . red ( 'Failed to compile.' ) ) ;
70
- console . log ( ) ;
71
- console . log ( err . message || err ) ;
72
- console . log ( ) ;
73
- process . exit ( 1 ) ;
74
- }
75
-
76
- // "invalid" event fires when you have changed a file, and Webpack is
77
- // recompiling a bundle. WebpackDevServer takes care to pause serving the
78
- // bundle, so if you refresh, it'll wait instead of serving the old one.
79
- // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
80
- compiler . plugin ( 'invalid' , function ( ) {
81
- if ( isInteractive ) {
82
- clearConsole ( ) ;
83
- }
84
- console . log ( 'Compiling...' ) ;
85
- } ) ;
86
-
87
- var isFirstCompile = true ;
88
-
89
- // "done" event fires when Webpack has finished recompiling the bundle.
90
- // Whether or not you have warnings or errors, you will get this event.
91
- compiler . plugin ( 'done' , function ( stats ) {
92
- if ( isInteractive ) {
93
- clearConsole ( ) ;
94
- }
95
46
96
- // We have switched off the default Webpack output in WebpackDevServer
97
- // options so we are going to "massage" the warnings and errors and present
98
- // them in a readable focused way.
99
- var messages = formatWebpackMessages ( stats . toJson ( { } , true ) ) ;
100
- var isSuccessful = ! messages . errors . length && ! messages . warnings . length ;
101
- var showInstructions = isSuccessful && ( isInteractive || isFirstCompile ) ;
102
-
103
- if ( isSuccessful ) {
104
- console . log ( chalk . green ( 'Compiled successfully!' ) ) ;
105
- }
106
-
107
- if ( showInstructions ) {
108
- console . log ( ) ;
109
- console . log ( 'The app is running at:' ) ;
110
- console . log ( ) ;
111
- console . log ( ' ' + chalk . cyan ( protocol + '://' + host + ':' + port + '/' ) ) ;
112
- console . log ( ) ;
113
- console . log ( 'Note that the development build is not optimized.' ) ;
114
- console . log ( 'To create a production build, use ' + chalk . cyan ( cli + ' run build' ) + '.' ) ;
115
- console . log ( ) ;
116
- isFirstCompile = false ;
117
- }
47
+ function run ( port ) {
48
+ var protocol = process . env . HTTPS === 'true' ? 'https' : 'http' ;
49
+ var host = process . env . HOST || 'localhost' ;
118
50
119
- // If errors exist, only show errors.
120
- if ( messages . errors . length ) {
121
- console . log ( chalk . red ( 'Failed to compile.' ) ) ;
122
- console . log ( ) ;
123
- messages . errors . forEach ( message => {
124
- console . log ( message ) ;
125
- console . log ( ) ;
126
- } ) ;
51
+ // Create a webpack compiler that is configured with custom messages.
52
+ var compiler = createWebpackCompiler ( config , function onReady ( showInstructions ) {
53
+ if ( ! showInstructions ) {
127
54
return ;
128
55
}
129
-
130
- // Show warnings if no errors were found.
131
- if ( messages . warnings . length ) {
132
- console . log ( chalk . yellow ( 'Compiled with warnings.' ) ) ;
133
- console . log ( ) ;
134
- messages . warnings . forEach ( message => {
135
- console . log ( message ) ;
136
- console . log ( ) ;
137
- } ) ;
138
- // Teach some ESLint tricks.
139
- console . log ( 'You may use special comments to disable some warnings.' ) ;
140
- console . log ( 'Use ' + chalk . yellow ( '// eslint-disable-next-line' ) + ' to ignore the next line.' ) ;
141
- console . log ( 'Use ' + chalk . yellow ( '/* eslint-disable */' ) + ' to ignore all warnings in a file.' ) ;
142
- }
143
- } ) ;
144
- }
145
-
146
- // We need to provide a custom onError function for httpProxyMiddleware.
147
- // It allows us to log custom error messages on the console.
148
- function onProxyError ( proxy ) {
149
- return function ( err , req , res ) {
150
- var host = req . headers && req . headers . host ;
151
- console . log (
152
- chalk . red ( 'Proxy error:' ) + ' Could not proxy request ' + chalk . cyan ( req . url ) +
153
- ' from ' + chalk . cyan ( host ) + ' to ' + chalk . cyan ( proxy ) + '.'
154
- ) ;
155
- console . log (
156
- 'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
157
- chalk . cyan ( err . code ) + ').'
158
- ) ;
159
56
console . log ( ) ;
160
-
161
- // And immediately send the proper error response to the client.
162
- // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
163
- if ( res . writeHead && ! res . headersSent ) {
164
- res . writeHead ( 500 ) ;
165
- }
166
- res . end ( 'Proxy error: Could not proxy request ' + req . url + ' from ' +
167
- host + ' to ' + proxy + ' (' + err . code + ').'
168
- ) ;
169
- }
170
- }
171
-
172
- function addMiddleware ( devServer ) {
173
- // `proxy` lets you to specify a fallback server during development.
174
- // Every unrecognized request will be forwarded to it.
175
- var proxy = require ( paths . appPackageJson ) . proxy ;
176
- devServer . use ( historyApiFallback ( {
177
- // Paths with dots should still use the history fallback.
178
- // See https://github.com/facebookincubator/create-react-app/issues/387.
179
- disableDotRule : true ,
180
- // For single page apps, we generally want to fallback to /index.html.
181
- // However we also want to respect `proxy` for API calls.
182
- // So if `proxy` is specified, we need to decide which fallback to use.
183
- // We use a heuristic: if request `accept`s text/html, we pick /index.html.
184
- // Modern browsers include text/html into `accept` header when navigating.
185
- // However API calls like `fetch()` won’t generally accept text/html.
186
- // If this heuristic doesn’t work well for you, don’t use `proxy`.
187
- htmlAcceptHeaders : proxy ?
188
- [ 'text/html' ] :
189
- [ 'text/html' , '*/*' ]
190
- } ) ) ;
191
- if ( proxy ) {
192
- if ( typeof proxy !== 'string' ) {
193
- console . log ( chalk . red ( 'When specified, "proxy" in package.json must be a string.' ) ) ;
194
- console . log ( chalk . red ( 'Instead, the type of "proxy" was "' + typeof proxy + '".' ) ) ;
195
- console . log ( chalk . red ( 'Either remove "proxy" from package.json, or make it a string.' ) ) ;
196
- process . exit ( 1 ) ;
197
- }
198
-
199
- // Otherwise, if proxy is specified, we will let it handle any request.
200
- // There are a few exceptions which we won't send to the proxy:
201
- // - /index.html (served as HTML5 history API fallback)
202
- // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
203
- // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
204
- // Tip: use https://jex.im/regulex/ to visualize the regex
205
- var mayProxy = / ^ (? ! \/ ( i n d e x \. h t m l $ | .* \. h o t - u p d a t e \. j s o n $ | s o c k j s - n o d e \/ ) ) .* $ / ;
206
-
207
- // Pass the scope regex both to Express and to the middleware for proxying
208
- // of both HTTP and WebSockets to work without false positives.
209
- var hpm = httpProxyMiddleware ( pathname => mayProxy . test ( pathname ) , {
210
- target : proxy ,
211
- logLevel : 'silent' ,
212
- onProxyReq : function ( proxyReq , req , res ) {
213
- // Browers may send Origin headers even with same-origin
214
- // requests. To prevent CORS issues, we have to change
215
- // the Origin to match the target URL.
216
- if ( proxyReq . getHeader ( 'origin' ) ) {
217
- proxyReq . setHeader ( 'origin' , proxy ) ;
218
- }
219
- } ,
220
- onError : onProxyError ( proxy ) ,
221
- secure : false ,
222
- changeOrigin : true ,
223
- ws : true ,
224
- xfwd : true
225
- } ) ;
226
- devServer . use ( mayProxy , hpm ) ;
227
-
228
- // Listen for the websocket 'upgrade' event and upgrade the connection.
229
- // If this is not done, httpProxyMiddleware will not try to upgrade until
230
- // an initial plain HTTP request is made.
231
- devServer . listeningApp . on ( 'upgrade' , hpm . upgrade ) ;
232
- }
233
-
234
- // Finally, by now we have certainly resolved the URL.
235
- // It may be /index.html, so let the dev server try serving it again.
236
- devServer . use ( devServer . middleware ) ;
237
- }
238
-
239
- function runDevServer ( host , port , protocol ) {
240
- var devServer = new WebpackDevServer ( compiler , {
241
- // Enable gzip compression of generated files.
242
- compress : true ,
243
- // Silence WebpackDevServer's own logs since they're generally not useful.
244
- // It will still show compile warnings and errors with this setting.
245
- clientLogLevel : 'none' ,
246
- // By default WebpackDevServer serves physical files from current directory
247
- // in addition to all the virtual build products that it serves from memory.
248
- // This is confusing because those files won’t automatically be available in
249
- // production build folder unless we copy them. However, copying the whole
250
- // project directory is dangerous because we may expose sensitive files.
251
- // Instead, we establish a convention that only files in `public` directory
252
- // get served. Our build script will copy `public` into the `build` folder.
253
- // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
254
- // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
255
- // In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
256
- // Note that we only recommend to use `public` folder as an escape hatch
257
- // for files like `favicon.ico`, `manifest.json`, and libraries that are
258
- // for some reason broken when imported through Webpack. If you just want to
259
- // use an image, put it in `src` and `import` it from JavaScript instead.
260
- contentBase : paths . appPublic ,
261
- // By default files from `contentBase` will not trigger a page reload.
262
- watchContentBase : true ,
263
- // Enable hot reloading server. It will provide /sockjs-node/ endpoint
264
- // for the WebpackDevServer client so it can learn when the files were
265
- // updated. The WebpackDevServer client is included as an entry point
266
- // in the Webpack development configuration. Note that only changes
267
- // to CSS are currently hot reloaded. JS changes will refresh the browser.
268
- hot : true ,
269
- // It is important to tell WebpackDevServer to use the same "root" path
270
- // as we specified in the config. In development, we always serve from /.
271
- publicPath : config . output . publicPath ,
272
- // WebpackDevServer is noisy by default so we emit custom message instead
273
- // by listening to the compiler events with `compiler.plugin` calls above.
274
- quiet : true ,
275
- // Reportedly, this avoids CPU overload on some systems.
276
- // https://github.com/facebookincubator/create-react-app/issues/293
277
- watchOptions : {
278
- ignored : / n o d e _ m o d u l e s /
279
- } ,
280
- // Enable HTTPS if the HTTPS environment variable is set to 'true'
281
- https : protocol === "https" ,
282
- host : host ,
283
- overlay : false ,
57
+ console . log ( 'The app is running at:' ) ;
58
+ console . log ( ) ;
59
+ console . log ( ' ' + chalk . cyan ( protocol + '://' + host + ':' + port + '/' ) ) ;
60
+ console . log ( ) ;
61
+ console . log ( 'Note that the development build is not optimized.' ) ;
62
+ console . log ( 'To create a production build, use ' + chalk . cyan ( cli + ' run build' ) + '.' ) ;
63
+ console . log ( ) ;
284
64
} ) ;
285
65
66
+ // Serve webpack assets generated by the compiler over a web sever.
67
+ var devServer = new WebpackDevServer ( compiler , devServerConfig ) ;
68
+
286
69
// Our custom middleware proxies requests to /index.html or a remote API.
287
- addMiddleware ( devServer ) ;
70
+ addWebpackMiddleware ( devServer ) ;
288
71
289
72
// Launch WebpackDevServer.
290
73
devServer . listen ( port , ( err , result ) => {
@@ -302,13 +85,6 @@ function runDevServer(host, port, protocol) {
302
85
} ) ;
303
86
}
304
87
305
- function run ( port ) {
306
- var protocol = process . env . HTTPS === 'true' ? "https" : "http" ;
307
- var host = process . env . HOST || 'localhost' ;
308
- setupCompiler ( host , port , protocol ) ;
309
- runDevServer ( host , port , protocol ) ;
310
- }
311
-
312
88
// We attempt to use the default port but if it is busy, we offer the user to
313
89
// run on a different port. `detect()` Promise resolves to the next free port.
314
90
detect ( DEFAULT_PORT ) . then ( port => {
0 commit comments