Skip to content

Commit c490b24

Browse files
robertaistleitnershellscape
authored andcommitted
allow explicitly setting the protocol from the public option (#1117)
* allow explicitly setting the protocol from the public option * add feedback from PR + add example + found one other glitch that auto-reload doesn't work in iframes since it tries to reload the iframe itself (which has src `about:blank`) and therefore cannot be reloaded properly. I'm now checking for protocol `about:` and traverse upwards until a reloadable window can be found. Feedback on this fix is welcome! * fix linting issues * provide tests for createDomain helper function + found a bug due to tests: `url.parse` doesn't properly parse a provided `public` option since it counts everything before the port colon as the protocol which is just wrong. I replaced it with a protocol regex. * increase timeout for https test which exceeds default 2000ms * move info log to the place where the reload happens * apply feedback * remove docker stuff from examples (minimize example) * use setInterval and clearInterval instead of do while loop when getting root window for reload * increase test timeout for https to 60 seconds
1 parent ee7231b commit c490b24

File tree

7 files changed

+155
-2
lines changed

7 files changed

+155
-2
lines changed

client/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,25 @@ function reloadApp() {
218218
self.postMessage('webpackHotUpdate' + currentHash, '*');
219219
}
220220
} else {
221+
let rootWindow = self;
222+
// use parent window for reload (in case we're in an iframe with no valid src)
223+
const intervalId = self.setInterval(function findRootWindow() {
224+
if (rootWindow.location.protocol !== 'about:') {
225+
// reload immediately if protocol is valid
226+
applyReload(rootWindow, intervalId);
227+
} else {
228+
rootWindow = rootWindow.parent;
229+
if (rootWindow.parent === rootWindow) {
230+
// if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways
231+
applyReload(rootWindow, intervalId);
232+
}
233+
}
234+
});
235+
}
236+
237+
function applyReload(rootWindow, intervalId) {
238+
clearInterval(intervalId);
221239
log.info('[WDS] App updated. Reloading...');
222-
self.location.reload();
240+
rootWindow.location.reload();
223241
}
224242
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# CLI - public protocol
2+
3+
NOTE: replace `<insert local ip>` with your local ip.
4+
5+
```shell
6+
node ../../bin/webpack-dev-server.js
7+
```
8+
9+
You're now able to explicitly define the protocol used with the `public` option (have a look to the config provided in `webpack.config.js`).
10+
11+
## What should happen
12+
13+
If you open your browser at `http://localhost:8080` you'll see that dev-server tries to establish a connection to `/sockjs-node` via the explicitly defined `https://localhost:8080`. This fails of course since we're not hosting https.

examples/cli-public-protocol/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
3+
document.open();
4+
document.write('Please check the sockjs-info request in your dev-tools, it should try to connect to the protocol + server defined in the public setting.');
5+
document.close();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="bundle.js" type="text/javascript" charset="utf-8"></script>
5+
</head>
6+
<body>
7+
</body>
8+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
module.exports = {
4+
context: __dirname,
5+
entry: './app.js',
6+
devServer: {
7+
host: '0.0.0.0',
8+
public: 'https://localhost:8080',
9+
disableHostCheck: true
10+
}
11+
};

lib/util/createDomain.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ module.exports = function createDomain(options, listeningApp) {
1010
const port = options.socket ? 0 : appPort;
1111
const hostname = options.useLocalIp ? internalIp.v4() : options.host;
1212

13+
// use explicitly defined public url (prefix with protocol if not explicitly given)
14+
if (options.public) {
15+
return /^[a-zA-Z]+:\/\//.test(options.public) ? `${options.public}` : `${protocol}://${options.public}`;
16+
}
1317
// the formatted domain (url without path) of the webpack server
14-
return options.public ? `${protocol}://${options.public}` : url.format({
18+
return url.format({
1519
protocol,
1620
hostname,
1721
port

test/Util.test.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'use strict';
2+
3+
const webpack = require('webpack');
4+
const internalIp = require('internal-ip');
5+
const Server = require('../lib/Server');
6+
const createDomain = require('../lib/util/createDomain');
7+
const config = require('./fixtures/simple-config/webpack.config');
8+
9+
describe('check utility funcitons', () => {
10+
let compiler;
11+
before(() => {
12+
compiler = webpack(config);
13+
});
14+
15+
const tests = [{
16+
name: 'default',
17+
options: {
18+
host: 'localhost',
19+
port: 8080
20+
},
21+
expected: 'http://localhost:8080'
22+
}, {
23+
name: 'https',
24+
options: {
25+
host: 'localhost',
26+
port: 8080,
27+
https: true
28+
},
29+
expected: 'https://localhost:8080',
30+
timeout: 60000
31+
}, {
32+
name: 'override with public',
33+
options: {
34+
host: 'localhost',
35+
port: 8080,
36+
public: 'myhost.test'
37+
},
38+
expected: 'http://myhost.test'
39+
}, {
40+
name: 'override with public (port)',
41+
options: {
42+
host: 'localhost',
43+
port: 8080,
44+
public: 'myhost.test:9090'
45+
},
46+
expected: 'http://myhost.test:9090'
47+
}, {
48+
name: 'override with public (protocol)',
49+
options: {
50+
host: 'localhost',
51+
port: 8080,
52+
public: 'https://myhost.test'
53+
},
54+
expected: 'https://myhost.test'
55+
}, {
56+
name: 'override with public (protocol + port)',
57+
options: {
58+
host: 'localhost',
59+
port: 8080,
60+
public: 'https://myhost.test:9090'
61+
},
62+
expected: 'https://myhost.test:9090'
63+
}, {
64+
name: 'localIp',
65+
options: {
66+
useLocalIp: true,
67+
port: 8080
68+
},
69+
expected: `http://${internalIp.v4()}:8080`
70+
}];
71+
72+
tests.forEach((t) => {
73+
const itInstance = it(`test createDomain '${t.name}'`, (done) => {
74+
const options = t.options;
75+
const server = new Server(compiler, options);
76+
const expected = t.expected;
77+
server.listen(options.port, options.host, (err) => {
78+
if (err) {
79+
done(err);
80+
}
81+
const generatedDomain = createDomain(options, server.listeningApp);
82+
if (generatedDomain !== expected) {
83+
done(`generated domain ${generatedDomain} doesn't match expected ${expected}`);
84+
} else {
85+
done();
86+
}
87+
server.close();
88+
});
89+
});
90+
if (t.timeout) {
91+
itInstance.timeout(t.timeout);
92+
}
93+
});
94+
});

0 commit comments

Comments
 (0)