@@ -13,11 +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 historyApiFallback = require ( 'connect-history-api-fallback' ) ;
17
+ var httpProxyMiddleware = require ( 'http-proxy-middleware' ) ;
16
18
var execSync = require ( 'child_process' ) . execSync ;
17
19
var opn = require ( 'opn' ) ;
18
20
var detect = require ( 'detect-port' ) ;
19
21
var prompt = require ( './utils/prompt' ) ;
20
22
var config = require ( '../config/webpack.config.dev' ) ;
23
+ var paths = require ( '../config/paths' ) ;
21
24
22
25
// Tools like Cloud9 rely on this
23
26
var DEFAULT_PORT = process . env . PORT || 3000 ;
@@ -150,13 +153,56 @@ function openBrowser(port) {
150
153
opn ( 'http://localhost:' + port + '/' ) ;
151
154
}
152
155
156
+ function addMiddleware ( devServer ) {
157
+ // `devProxy` lets you to specify a fallback server during development.
158
+ // Every unrecognized request will be forwarded to it.
159
+ var devProxy = require ( paths . appPackageJson ) . devProxy ;
160
+ devServer . use ( historyApiFallback ( {
161
+ // For single page apps, we generally want to fallback to /index.html.
162
+ // However we also want to respect `devProxy` for API calls.
163
+ // So if `devProxy` is specified, we need to decide which fallback to use.
164
+ // We use a heuristic: if request `accept`s text/html, we pick /index.html.
165
+ // Modern browsers include text/html into `accept` header when navigating.
166
+ // However API calls like `fetch()` won’t generally won’t accept text/html.
167
+ // If this heuristic doesn’t work well for you, don’t use `devProxy`.
168
+ htmlAcceptHeaders : devProxy ?
169
+ [ 'text/html' ] :
170
+ [ 'text/html' , '*/*' ]
171
+ } ) ) ;
172
+ if ( devProxy ) {
173
+ if ( typeof devProxy !== 'string' ) {
174
+ console . log ( chalk . red ( 'When specified, "devProxy" in package.json must be a string.' ) ) ;
175
+ console . log ( chalk . red ( 'Instead, the type of "devProxy" was "' + typeof devProxy + '".' ) ) ;
176
+ console . log ( chalk . red ( 'Either remove "devProxy" from package.json, or make it a string.' ) ) ;
177
+ process . exit ( 1 ) ;
178
+ }
179
+
180
+ // Otherwise, if devProxy is specified, we will let it handle any request
181
+ // that isn't /index.html or /sockjs-node/* (used for hot reloading).
182
+ var safeToProxy = / ^ (? ! \/ ( i n d e x \. h t m l | s o c k j s - n o d e \/ .* ) ) .* $ / ;
183
+ devServer . use ( safeToProxy ,
184
+ // Pass the scope regex both to Express and to the middleware for proxying
185
+ // of both HTTP and WebSockets to work without false positives.
186
+ httpProxyMiddleware ( pathname => safeToProxy . test ( pathname ) , {
187
+ target : devProxy ,
188
+ logLevel : 'silent' ,
189
+ ws : true
190
+ } )
191
+ ) ;
192
+ }
193
+ // Finally, by now we have certainly resolved the URL.
194
+ // It may be /index.html, so let the dev server try serving it again.
195
+ devServer . use ( devServer . middleware ) ;
196
+ }
197
+
153
198
function runDevServer ( port ) {
154
- new WebpackDevServer ( compiler , {
155
- historyApiFallback : true ,
199
+ var devServer = new WebpackDevServer ( compiler , {
156
200
hot : true , // Note: only CSS is currently hot reloaded
157
201
publicPath : config . output . publicPath ,
158
202
quiet : true
159
- } ) . listen ( port , ( err , result ) => {
203
+ } ) ;
204
+ addMiddleware ( devServer ) ;
205
+ devServer . listen ( port , ( err , result ) => {
160
206
if ( err ) {
161
207
return console . log ( err ) ;
162
208
}
0 commit comments