Skip to content

Commit 31301a2

Browse files
committed
feat: improve host option
1 parent 3ad750e commit 31301a2

File tree

10 files changed

+69
-44
lines changed

10 files changed

+69
-44
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ Options:
9696
--setup-exit-signals Close and exit the process on SIGINT and SIGTERM.
9797
--no-setup-exit-signals Do not close and exit the process on SIGNIT and SIGTERM.
9898
--open [value] Open the default browser, or optionally specify a browser name.
99-
--use-local-ip Open default browser with local IP.
10099
--open-page <value...> Open default browser with the specified page.
101100
--client-logging <value> Log level in the browser (none, error, warn, info, log, verbose).
102101
--history-api-fallback Fallback to /index.html for Single Page Applications.

bin/cli-flags.js

-10
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,6 @@ module.exports = {
125125
description:
126126
'Open the default browser, or optionally specify a browser name.',
127127
},
128-
{
129-
name: 'use-local-ip',
130-
type: Boolean,
131-
configs: [
132-
{
133-
type: 'boolean',
134-
},
135-
],
136-
description: 'Open default browser with local IP.',
137-
},
138128
{
139129
name: 'open-page',
140130
type: String,

lib/Server.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,14 @@ class Server {
518518
this.server = http.createServer(this.app);
519519
}
520520

521-
this.server.on('error', (err) => {
522-
throw err;
521+
this.server.on('error', (error) => {
522+
if (error.code === 'EADDRNOTAVAIL' || error.code === 'ENOTFOUND') {
523+
this.logger.error(
524+
`Address "${this.hostname}" is not available. Try with a different value for "host" option.\n ${error}`
525+
);
526+
process.exit(2);
527+
}
528+
throw error;
523529
});
524530
}
525531

@@ -724,7 +730,15 @@ class Server {
724730
}
725731

726732
listen(port, hostname, fn) {
727-
this.hostname = hostname;
733+
if (hostname === 'local-ip') {
734+
this.hostname = internalIp.v4.sync() || internalIp.v6.sync();
735+
} else if (hostname === 'local-ipv4') {
736+
this.hostname = internalIp.v4.sync();
737+
} else if (hostname === 'local-ipv6') {
738+
this.hostname = internalIp.v6.sync();
739+
} else {
740+
this.hostname = hostname;
741+
}
728742

729743
if (typeof port !== 'undefined' && port !== this.options.port) {
730744
this.logger.warn(
@@ -737,8 +751,7 @@ class Server {
737751
// eslint-disable-next-line no-shadow
738752
.then((port) => {
739753
this.port = port;
740-
741-
return this.server.listen(port, hostname, (error) => {
754+
return this.server.listen(port, this.hostname, (error) => {
742755
if (this.options.hot || this.options.liveReload) {
743756
this.createSocketServer();
744757
}

lib/options.json

+1-5
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,6 @@
374374
"enum": ["sockjs", "ws"]
375375
}
376376
]
377-
},
378-
"useLocalIp": {
379-
"type": "boolean"
380377
}
381378
},
382379
"errorMessage": {
@@ -403,8 +400,7 @@
403400
"public": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpublic)",
404401
"setupExitSignals": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserversetupexitsignals)",
405402
"static": "should be {Boolean|String|Object|Array} (https://webpack.js.org/configuration/dev-server/#devserverstatic)",
406-
"transportMode": "should be {String|Object} (https://webpack.js.org/configuration/dev-server/#devservertransportmode)",
407-
"useLocalIp": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserveruselocalip)"
403+
"transportMode": "should be {String|Object} (https://webpack.js.org/configuration/dev-server/#devservertransportmode)"
408404
}
409405
},
410406
"additionalProperties": false

lib/utils/createDomain.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
'use strict';
22

33
const url = require('url');
4-
const ip = require('internal-ip');
54

65
function createDomain(options, server) {
76
const protocol = options.https ? 'https' : 'http';
87
// use location hostname and port by default in createSocketUrl
98
// ipv6 detection is not required as 0.0.0.0 is just used as a placeholder
109
let hostname;
1110

12-
if (options.useLocalIp) {
13-
hostname = ip.v4.sync() || '0.0.0.0';
14-
} else if (server) {
11+
if (server) {
1512
hostname = server.address().address;
1613
} else {
1714
hostname = '0.0.0.0';

test/__snapshots__/Validation.test.js.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ exports[`Validation validation should fail validation for invalid \`static\` con
4343
exports[`Validation validation should fail validation for no additional properties 1`] = `
4444
"Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
4545
- configuration has an unknown property 'additional'. These properties are valid:
46-
object { bonjour?, client?, compress?, dev?, firewall?, headers?, historyApiFallback?, host?, hot?, http2?, https?, liveReload?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, openPage?, port?, proxy?, public?, setupExitSignals?, static?, transportMode?, useLocalIp? }"
46+
object { bonjour?, client?, compress?, dev?, firewall?, headers?, historyApiFallback?, host?, hot?, http2?, https?, liveReload?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, openPage?, port?, proxy?, public?, setupExitSignals?, static?, transportMode? }"
4747
`;

test/cli/__snapshots__/cli.test.js.snap

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ exports[`CLI --host <IPv4>: stderr 1`] = `
2020
<i> [webpack-dev-server] Content not from webpack is served from '<cwd>/public' directory"
2121
`;
2222
23+
exports[`CLI --host <local-ip>: stderr 1`] = `
24+
"<i> [webpack-dev-server] Project is running at:
25+
<i> [webpack-dev-server] On Your Network (IPv4): http://<network-ip-v4>:<port>/
26+
<i> [webpack-dev-server] Content not from webpack is served from '<cwd>/public' directory"
27+
`;
28+
29+
exports[`CLI --host <local-ipv4>: stderr 1`] = `
30+
"<i> [webpack-dev-server] Project is running at:
31+
<i> [webpack-dev-server] On Your Network (IPv4): http://<network-ip-v4>:<port>/
32+
<i> [webpack-dev-server] Content not from webpack is served from '<cwd>/public' directory"
33+
`;
34+
2335
exports[`CLI --host 0.0.0.0 (IPv4): stderr 1`] = `
2436
"<i> [webpack-dev-server] Project is running at:
2537
<i> [webpack-dev-server] Loopback: http://localhost:<port>/

test/cli/cli.test.js

+36
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,42 @@ describe('CLI', () => {
190190
.catch(done);
191191
});
192192

193+
it('--host <local-ip>', (done) => {
194+
testBin('--host local-ip')
195+
.then((output) => {
196+
expect(normalizeStderr(output.stderr)).toMatchSnapshot('stderr');
197+
198+
done();
199+
})
200+
.catch(done);
201+
});
202+
203+
it('--host <local-ipv4>', (done) => {
204+
testBin('--host local-ipv4')
205+
.then((output) => {
206+
expect(normalizeStderr(output.stderr)).toMatchSnapshot('stderr');
207+
208+
done();
209+
})
210+
.catch(done);
211+
});
212+
213+
it('should throw error for invalid host', (done) => {
214+
const cliPath = path.resolve(__dirname, '../../bin/webpack-dev-server.js');
215+
const cwd = path.resolve(__dirname, '../fixtures/cli');
216+
const cp = execa('node', [cliPath, '--host', 'invalid'], { cwd });
217+
218+
cp.stderr.on('data', (chunk) => {
219+
expect(chunk.toString()).toContain(
220+
`Address "invalid" is not available. Try with a different value for "host" option.`
221+
);
222+
});
223+
224+
cp.on('exit', () => {
225+
done();
226+
});
227+
});
228+
193229
it('--host localhost --port 9999', (done) => {
194230
testBin('--host localhost --port 9999')
195231
.then((output) => {

test/options.test.js

-4
Original file line numberDiff line numberDiff line change
@@ -500,10 +500,6 @@ describe('options', () => {
500500
},
501501
],
502502
},
503-
useLocalIp: {
504-
success: [false],
505-
failure: [''],
506-
},
507503
};
508504

509505
Object.keys(cases).forEach((key) => {

test/server/utils/createDomain.test.js

-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const webpack = require('webpack');
4-
const internalIp = require('internal-ip');
54
const Server = require('../../../lib/Server');
65
const createDomain = require('../../../lib/utils/createDomain');
76
const [port1, port2] = require('../../ports-map').createDomain;
@@ -89,19 +88,6 @@ describe('createDomain', () => {
8988
},
9089
expected: [`https://myhost.test:${port2}`],
9190
},
92-
{
93-
name: 'localIp',
94-
options: {
95-
useLocalIp: true,
96-
port: port1,
97-
},
98-
expected: [
99-
`http://${internalIp.v4.sync()}:${port1}`,
100-
`https://localhost:${port1}`,
101-
`https://127.0.0.1:${port1}`,
102-
`https://[::1]:${port1}`,
103-
],
104-
},
10591
];
10692

10793
tests.forEach((test) => {

0 commit comments

Comments
 (0)