Skip to content

Commit d5ebaeb

Browse files
committed
Add proxy option to package.json
This allows users to avoid CORS in simple projects that are hosted on the same server as backend.
1 parent 997b432 commit d5ebaeb

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"babel-runtime": "6.11.6",
4343
"case-sensitive-paths-webpack-plugin": "1.1.3",
4444
"chalk": "1.1.3",
45+
"connect-history-api-fallback": "1.2.0",
4546
"cross-spawn": "4.0.0",
4647
"css-loader": "0.23.1",
4748
"detect-port": "1.0.0",
@@ -57,6 +58,7 @@
5758
"fs-extra": "0.30.0",
5859
"gzip-size": "3.0.0",
5960
"html-webpack-plugin": "2.22.0",
61+
"http-proxy-middleware": "0.17.0",
6062
"json-loader": "0.5.4",
6163
"object-assign": "4.1.0",
6264
"opn": "4.0.2",

scripts/start.js

+53-6
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ var path = require('path');
1313
var chalk = require('chalk');
1414
var webpack = require('webpack');
1515
var WebpackDevServer = require('webpack-dev-server');
16+
var historyApiFallback = require('connect-history-api-fallback');
17+
var httpProxyMiddleware = require('http-proxy-middleware');
1618
var execSync = require('child_process').execSync;
1719
var opn = require('opn');
1820
var detect = require('detect-port');
1921
var prompt = require('./utils/prompt');
2022
var config = require('../config/webpack.config.dev');
23+
var paths = require('../config/paths');
2124

2225
// Tools like Cloud9 rely on this.
2326
var DEFAULT_PORT = process.env.PORT || 3000;
@@ -165,12 +168,54 @@ function openBrowser(port) {
165168
opn('http://localhost:' + port + '/');
166169
}
167170

171+
function addMiddleware(devServer) {
172+
// `proxy` lets you to specify a fallback server during development.
173+
// Every unrecognized request will be forwarded to it.
174+
var proxy = require(paths.appPackageJson).proxy;
175+
devServer.use(historyApiFallback({
176+
// For single page apps, we generally want to fallback to /index.html.
177+
// However we also want to respect `proxy` for API calls.
178+
// So if `proxy` is specified, we need to decide which fallback to use.
179+
// We use a heuristic: if request `accept`s text/html, we pick /index.html.
180+
// Modern browsers include text/html into `accept` header when navigating.
181+
// However API calls like `fetch()` won’t generally won’t accept text/html.
182+
// If this heuristic doesn’t work well for you, don’t use `proxy`.
183+
htmlAcceptHeaders: proxy ?
184+
['text/html'] :
185+
['text/html', '*/*']
186+
}));
187+
if (proxy) {
188+
if (typeof proxy !== 'string') {
189+
console.log(chalk.red('When specified, "proxy" in package.json must be a string.'));
190+
console.log(chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".'));
191+
console.log(chalk.red('Either remove "proxy" from package.json, or make it a string.'));
192+
process.exit(1);
193+
}
194+
195+
// Otherwise, if proxy is specified, we will let it handle any request.
196+
// There are a few exceptions which we won't send to the proxy:
197+
// - /index.html (served as HTML5 history API fallback)
198+
// - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
199+
// - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
200+
var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
201+
devServer.use(mayProxy,
202+
// Pass the scope regex both to Express and to the middleware for proxying
203+
// of both HTTP and WebSockets to work without false positives.
204+
httpProxyMiddleware(pathname => mayProxy.test(pathname), {
205+
target: proxy,
206+
logLevel: 'silent',
207+
secure: false,
208+
changeOrigin: true
209+
})
210+
);
211+
}
212+
// Finally, by now we have certainly resolved the URL.
213+
// It may be /index.html, so let the dev server try serving it again.
214+
devServer.use(devServer.middleware);
215+
}
216+
168217
function runDevServer(port) {
169-
// Launch WebpackDevServer.
170-
new WebpackDevServer(compiler, {
171-
// When an unrecognized URL is requested (e.g. localhost:3000/todos),
172-
// assume that this is a single-page app, and serve index.html.
173-
historyApiFallback: true,
218+
var devServer = new WebpackDevServer(compiler, {
174219
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
175220
// for the WebpackDevServer client so it can learn when the files were
176221
// updated. The WebpackDevServer client is included as an entry point
@@ -188,7 +233,9 @@ function runDevServer(port) {
188233
watchOptions: {
189234
ignored: /node_modules/
190235
}
191-
}).listen(port, (err, result) => {
236+
});
237+
addMiddleware(devServer);
238+
devServer.listen(port, (err, result) => {
192239
if (err) {
193240
return console.log(err);
194241
}

0 commit comments

Comments
 (0)