Skip to content

Commit 155d036

Browse files
alexkuzSpaceK33z
authored andcommitted
Proxy config hot reloading (#605)
1 parent 325ef59 commit 155d036

File tree

6 files changed

+133
-8
lines changed

6 files changed

+133
-8
lines changed

examples/proxy-hot-reload/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Proxy: hot reload
2+
3+
```shell
4+
node ../../bin/webpack-dev-server.js --open
5+
```
6+
7+
Enables hot reloading for proxy config. If function is provided instead of
8+
object, dev server calls it on each request to get proxy config and replaces proxy middleware if config was changed.
9+
10+
## What should happen
11+
12+
The script should open `http://localhost:8080/`. It should show "It's working."
13+
14+
Go to `http://localhost:8080/api/users`. It should show a couple of JSON objects.
15+
16+
While dev server is running, open `proxy-config.js` and replace
17+
```js
18+
module.exports = {
19+
target: 'http://jsonplaceholder.typicode.com/',
20+
pathRewrite: {
21+
'^/api': ''
22+
}
23+
};
24+
```
25+
with
26+
```js
27+
module.exports = {
28+
target: 'http://reqres.in/'
29+
};
30+
```
31+
32+
Now `http://localhost:8080/api/users` should return a response from `http://reqres.in/`.

examples/proxy-hot-reload/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
document.write("It's working.");

examples/proxy-hot-reload/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="bundle.js" type="text/javascript" charset="utf-8"></script>
5+
</head>
6+
<body>
7+
<h1>Example: proxy - hot reload</h1>
8+
<p>Change config in <code>proxy-config.js</code> and open <a href="/api/users">/api/users</a></p>
9+
</body>
10+
</html>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**/
2+
module.exports = {
3+
target: 'http://jsonplaceholder.typicode.com/',
4+
pathRewrite: {
5+
'^/api': ''
6+
}
7+
};
8+
/**/
9+
10+
//
11+
// Replace it with following and save the file:
12+
//
13+
14+
/** /
15+
module.exports = {
16+
target: 'http://reqres.in/'
17+
};
18+
/**/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var fs = require('fs');
2+
3+
var proxyConfig = require('./proxy-config');
4+
var proxyOptions = {
5+
context: '/api',
6+
target: proxyConfig.target,
7+
pathRewrite: proxyConfig.pathRewrite,
8+
changeOrigin: true
9+
};
10+
11+
fs.watch('./proxy-config.js', function() {
12+
delete require.cache[require.resolve('./proxy-config')];
13+
try {
14+
var newProxyConfig = require('./proxy-config');
15+
if(proxyOptions.target !== newProxyConfig.target) {
16+
console.log('Proxy target changed:', newProxyConfig.target);
17+
proxyOptions = {
18+
context: '/api',
19+
target: newProxyConfig.target,
20+
pathRewrite: newProxyConfig.pathRewrite,
21+
changeOrigin: true
22+
};
23+
}
24+
} catch(e) {}
25+
});
26+
27+
module.exports = {
28+
context: __dirname,
29+
entry: "./app.js",
30+
devServer: {
31+
proxy: [
32+
function() {
33+
return proxyOptions;
34+
}
35+
]
36+
}
37+
};

lib/Server.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,26 +162,53 @@ function Server(compiler, options) {
162162
});
163163
}
164164

165+
var getProxyMiddleware = function(proxyConfig) {
166+
var context = proxyConfig.context || proxyConfig.path;
167+
168+
// It is possible to use the `bypass` method without a `target`.
169+
// However, the proxy middleware has no use in this case, and will fail to instantiate.
170+
if(proxyConfig.target) {
171+
return httpProxyMiddleware(context, proxyConfig);
172+
}
173+
}
174+
165175
/**
166176
* Assume a proxy configuration specified as:
167177
* proxy: [
168178
* {
169179
* context: ...,
170180
* ...options...
171-
* }
181+
* },
182+
* // or:
183+
* function() {
184+
* return {
185+
* context: ...,
186+
* ...options...
187+
* };
188+
* }
172189
* ]
173190
*/
174-
options.proxy.forEach(function(proxyConfig) {
175-
var bypass = typeof proxyConfig.bypass === 'function';
176-
var context = proxyConfig.context || proxyConfig.path;
191+
options.proxy.forEach(function(proxyConfigOrCallback) {
192+
var proxyConfig;
177193
var proxyMiddleware;
178-
// It is possible to use the `bypass` method without a `target`.
179-
// However, the proxy middleware has no use in this case, and will fail to instantiate.
180-
if(proxyConfig.target) {
181-
proxyMiddleware = httpProxyMiddleware(context, proxyConfig);
194+
195+
if(typeof proxyConfigOrCallback === 'function') {
196+
proxyConfig = proxyConfigOrCallback();
197+
} else {
198+
proxyConfig = proxyConfigOrCallback;
182199
}
183200

201+
proxyMiddleware = getProxyMiddleware(proxyConfig);
202+
184203
app.use(function(req, res, next) {
204+
if(typeof proxyConfigOrCallback === 'function') {
205+
var newProxyConfig = proxyConfigOrCallback();
206+
if(newProxyConfig !== proxyConfig) {
207+
proxyConfig = newProxyConfig;
208+
proxyMiddleware = getProxyMiddleware(proxyConfig);
209+
}
210+
}
211+
var bypass = typeof proxyConfig.bypass === 'function';
185212
var bypassUrl = bypass && proxyConfig.bypass(req, res, proxyConfig) || false;
186213

187214
if(bypassUrl) {

0 commit comments

Comments
 (0)