1- process . env . NODE_ENV = 'development' ;
2- // Load environment variables from .env file.
3- // Suppress warnings if this file is missing.
4- require ( 'dotenv' ) . config ( { silent : true } ) ;
5-
1+ const fs = require ( 'fs' ) ;
62const pathExists = require ( 'path-exists' ) ;
73const chalk = require ( 'chalk' ) ;
84const webpack = require ( 'webpack' ) ;
@@ -11,6 +7,12 @@ const config = require('../config/webpack.config.dev');
117const formatWebpackMessages = require ( 'react-dev-utils/formatWebpackMessages' ) ;
128const clearConsole = require ( 'react-dev-utils/clearConsole' ) ;
139const openBrowser = require ( 'react-dev-utils/openBrowser' ) ;
10+ const historyApiFallback = require ( 'connect-history-api-fallback' ) ;
11+ const httpProxyMiddleware = require ( 'http-proxy-middleware' ) ;
12+
13+ // Load environment variables from .env file.
14+ // Suppress warnings if this file is missing.
15+ require ( 'dotenv' ) . config ( { silent : true } ) ;
1416
1517if ( pathExists . sync ( 'elm-package.json' ) === false ) {
1618 console . log ( 'Please, run the build script from project root directory' ) ;
@@ -54,14 +56,108 @@ compiler.plugin('done', function (stats) {
5456 }
5557} ) ;
5658
59+
60+ // We need to provide a custom onError function for httpProxyMiddleware.
61+ // It allows us to log custom error messages on the console.
62+ function onProxyError ( proxy ) {
63+ return function ( err , req , res ) {
64+ var host = req . headers && req . headers . host ;
65+ console . log (
66+ chalk . red ( 'Proxy error:' ) + ' Could not proxy request ' + chalk . cyan ( req . url ) +
67+ ' from ' + chalk . cyan ( host ) + ' to ' + chalk . cyan ( proxy ) + '.'
68+ ) ;
69+ console . log (
70+ 'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
71+ chalk . cyan ( err . code ) + ').'
72+ ) ;
73+ console . log ( ) ;
74+
75+ // And immediately send the proper error response to the client.
76+ // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
77+ if ( res . writeHead && ! res . headersSent ) {
78+ res . writeHead ( 500 ) ;
79+ }
80+ res . end ( 'Proxy error: Could not proxy request ' + req . url + ' from ' +
81+ host + ' to ' + proxy + ' (' + err . code + ').'
82+ ) ;
83+ } ;
84+ }
85+
86+ function addMiddleware ( devServer ) {
87+ // `proxy` lets you to specify a fallback server during development.
88+ // Every unrecognized request will be forwarded to it.
89+ var proxy = JSON . parse ( fs . readFileSync ( 'elm-package.json' , 'utf-8' ) ) . proxy ;
90+ devServer . use ( historyApiFallback ( {
91+ // Paths with dots should still use the history fallback.
92+ // See https://github.com/facebookincubator/create-react-app/issues/387.
93+ disableDotRule : true ,
94+ // For single page apps, we generally want to fallback to /index.html.
95+ // However we also want to respect `proxy` for API calls.
96+ // So if `proxy` is specified, we need to decide which fallback to use.
97+ // We use a heuristic: if request `accept`s text/html, we pick /index.html.
98+ // Modern browsers include text/html into `accept` header when navigating.
99+ // However API calls like `fetch()` won’t generally accept text/html.
100+ // If this heuristic doesn’t work well for you, don’t use `proxy`.
101+ htmlAcceptHeaders : proxy ?
102+ [ 'text/html' ] :
103+ [ 'text/html' , '*/*' ]
104+ } ) ) ;
105+ if ( proxy ) {
106+ if ( typeof proxy !== 'string' ) {
107+ console . log ( chalk . red ( 'When specified, "proxy" in package.json must be a string.' ) ) ;
108+ console . log ( chalk . red ( 'Instead, the type of "proxy" was "' + typeof proxy + '".' ) ) ;
109+ console . log ( chalk . red ( 'Either remove "proxy" from package.json, or make it a string.' ) ) ;
110+ process . exit ( 1 ) ;
111+ }
112+
113+ // Otherwise, if proxy is specified, we will let it handle any request.
114+ // There are a few exceptions which we won't send to the proxy:
115+ // - /index.html (served as HTML5 history API fallback)
116+ // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
117+ // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
118+ // Tip: use https://jex.im/regulex/ to visualize the regex
119+ 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 \/ ) ) .* $ / ;
120+
121+ // Pass the scope regex both to Express and to the middleware for proxying
122+ // of both HTTP and WebSockets to work without false positives.
123+ var hpm = httpProxyMiddleware ( pathname => mayProxy . test ( pathname ) , {
124+ target : proxy ,
125+ logLevel : 'silent' ,
126+ onProxyReq : function ( proxyReq ) {
127+ // Browers may send Origin headers even with same-origin
128+ // requests. To prevent CORS issues, we have to change
129+ // the Origin to match the target URL.
130+ if ( proxyReq . getHeader ( 'origin' ) ) {
131+ proxyReq . setHeader ( 'origin' , proxy ) ;
132+ }
133+ } ,
134+ onError : onProxyError ( proxy ) ,
135+ secure : false ,
136+ changeOrigin : true ,
137+ ws : true
138+ } ) ;
139+ devServer . use ( mayProxy , hpm ) ;
140+
141+ // Listen for the websocket 'upgrade' event and upgrade the connection.
142+ // If this is not done, httpProxyMiddleware will not try to upgrade until
143+ // an initial plain HTTP request is made.
144+ devServer . listeningApp . on ( 'upgrade' , hpm . upgrade ) ;
145+ }
146+
147+ // Finally, by now we have certainly resolved the URL.
148+ // It may be /index.html, so let the dev server try serving it again.
149+ devServer . use ( devServer . middleware ) ;
150+ }
151+
57152const devServer = new WebpackDevServer ( compiler , {
58153 hot : true ,
59154 inline : true ,
60155 publicPath : '/' ,
61- quiet : true ,
62- historyApiFallback : true ,
156+ quiet : true
63157} ) ;
64158
159+ addMiddleware ( devServer ) ;
160+
65161// Launch WebpackDevServer.
66162devServer . listen ( port , function ( err ) {
67163 if ( err ) {
0 commit comments