Skip to content

Commit 4b097e2

Browse files
hiroppyevilebottnawi
authored andcommitted
refactor: don't listen to http error event (#1924)
1 parent 0baa0e0 commit 4b097e2

File tree

4 files changed

+80
-87
lines changed

4 files changed

+80
-87
lines changed

bin/webpack-dev-server.js

+1-28
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ const Server = require('../lib/Server');
2323
const colors = require('../lib/utils/colors');
2424
const createConfig = require('../lib/utils/createConfig');
2525
const createLogger = require('../lib/utils/createLogger');
26-
const defaultTo = require('../lib/utils/defaultTo');
2726
const findPort = require('../lib/utils/findPort');
2827
const getVersions = require('../lib/utils/getVersions');
29-
const tryParseInt = require('../lib/utils/tryParseInt');
3028

3129
let server;
3230

@@ -197,7 +195,7 @@ function startDevServer(config, options) {
197195
});
198196
});
199197
} else {
200-
decidePort(server, options.port)
198+
findPort(options.port)
201199
.then((port) => {
202200
options.port = port;
203201
server.listen(options.port, options.host, (err) => {
@@ -212,29 +210,4 @@ function startDevServer(config, options) {
212210
}
213211
}
214212

215-
function decidePort(server, port) {
216-
return new Promise((resolve, reject) => {
217-
if (typeof port !== 'undefined') {
218-
resolve(port);
219-
} else {
220-
// Try to find unused port and listen on it for 3 times,
221-
// if port is not specified in options.
222-
// Because NaN == null is false, defaultTo fails if parseInt returns NaN
223-
// so the tryParseInt function is introduced to handle NaN
224-
const defaultPortRetry = defaultTo(
225-
tryParseInt(process.env.DEFAULT_PORT_RETRY),
226-
3
227-
);
228-
229-
// only run port finder if no port as been specified
230-
findPort(server, DEFAULT_PORT, defaultPortRetry, (err, port) => {
231-
if (err) {
232-
reject(err);
233-
}
234-
resolve(port);
235-
});
236-
}
237-
});
238-
}
239-
240213
processOptions(config);

lib/utils/findPort.js

+22-29
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,28 @@
11
'use strict';
22

3-
const portfinder = require('portfinder');
4-
5-
function runPortFinder(defaultPort, cb) {
6-
portfinder.basePort = defaultPort;
7-
portfinder.getPort((err, port) => {
8-
cb(err, port);
9-
});
10-
}
11-
12-
function findPort(server, defaultPort, defaultPortRetry, fn) {
13-
let tryCount = 0;
14-
const portFinderRunCb = (err, port) => {
15-
tryCount += 1;
16-
fn(err, port);
17-
};
18-
19-
server.listeningApp.on('error', (err) => {
20-
if (err && err.code !== 'EADDRINUSE') {
21-
throw err;
22-
}
23-
24-
if (tryCount >= defaultPortRetry) {
25-
fn(err);
26-
return;
27-
}
28-
29-
runPortFinder(defaultPort, portFinderRunCb);
3+
const { getPortPromise } = require('portfinder');
4+
const defaultTo = require('./defaultTo');
5+
const tryParseInt = require('./tryParseInt');
6+
7+
const defaultPort = 8080;
8+
9+
function findPort(port) {
10+
if (typeof port !== 'undefined') {
11+
return Promise.resolve(port);
12+
}
13+
// Try to find unused port and listen on it for 3 times,
14+
// if port is not specified in options.
15+
// Because NaN == null is false, defaultTo fails if parseInt returns NaN
16+
// so the tryParseInt function is introduced to handle NaN
17+
const defaultPortRetry = defaultTo(
18+
tryParseInt(process.env.DEFAULT_PORT_RETRY),
19+
3
20+
);
21+
22+
return getPortPromise({
23+
port: defaultPort,
24+
stopPort: defaultPort + defaultPortRetry,
3025
});
31-
32-
runPortFinder(defaultPort, portFinderRunCb);
3326
}
3427

3528
module.exports = findPort;

test/Util.test.js

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

3-
const EventEmitter = require('events');
4-
const assert = require('assert');
3+
const http = require('http');
54
const webpack = require('webpack');
65
const internalIp = require('internal-ip');
76
const Server = require('../lib/Server');
@@ -119,40 +118,65 @@ describe('check utility functions', () => {
119118
});
120119

121120
describe('findPort cli utility function', () => {
122-
let mockServer = null;
123-
124-
beforeEach(() => {
125-
mockServer = {
126-
listeningApp: new EventEmitter(),
127-
};
128-
});
121+
let dummyServers = [];
129122

130123
afterEach(() => {
131-
mockServer.listeningApp.removeAllListeners('error');
132-
mockServer = null;
124+
delete process.env.DEFAULT_PORT_RETRY;
125+
126+
return dummyServers
127+
.reduce((p, server) => {
128+
return p.then(() => {
129+
return new Promise((resolve) => {
130+
server.close(resolve);
131+
});
132+
});
133+
}, Promise.resolve())
134+
.then(() => {
135+
dummyServers = [];
136+
});
133137
});
134138

135-
it('should find empty port starting from defaultPort', (done) => {
136-
findPort(mockServer, 8180, 3, (err, port) => {
137-
assert(err == null);
138-
assert(port === 8180);
139-
done();
139+
function createDummyServers(n) {
140+
return [...new Array(n)].reduce((p, _, i) => {
141+
return p.then(() => {
142+
return new Promise((resolve) => {
143+
const server = http.createServer();
144+
dummyServers.push(server);
145+
server.listen(8080 + i, resolve);
146+
});
147+
});
148+
}, Promise.resolve());
149+
}
150+
151+
it('should return the port when the port is specified', () => {
152+
process.env.DEFAULT_PORT_RETRY = 5;
153+
154+
return findPort(8082).then((port) => {
155+
expect(port).toEqual(8082);
140156
});
141157
});
142158

143-
it('should retry finding port for up to defaultPortRetry times', (done) => {
144-
let count = 0;
145-
const defaultPortRetry = 5;
146-
findPort(mockServer, 8180, defaultPortRetry, (err) => {
147-
if (err == null) {
148-
count += 1;
149-
const mockError = new Error('EADDRINUSE');
150-
mockError.code = 'EADDRINUSE';
151-
mockServer.listeningApp.emit('error', mockError);
152-
return;
153-
}
154-
assert(count === defaultPortRetry);
155-
done();
156-
});
159+
it('should retry finding the port for up to defaultPortRetry times', () => {
160+
const retryCount = 5;
161+
162+
process.env.DEFAULT_PORT_RETRY = retryCount;
163+
164+
return createDummyServers(retryCount)
165+
.then(findPort)
166+
.then((port) => {
167+
expect(port).toEqual(8080 + retryCount);
168+
});
169+
});
170+
171+
it("should throw the error when the port isn't found", () => {
172+
const retryCount = 5;
173+
174+
process.env.DEFAULT_PORT_RETRY = retryCount;
175+
176+
return createDummyServers(10)
177+
.then(findPort)
178+
.catch((err) => {
179+
expect(err.message).toMatchSnapshot();
180+
});
157181
});
158182
});

test/__snapshots__/Util.test.js.snap

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`findPort cli utility function should throw the error when the port isn't found 1`] = `"No open ports found in between 8080 and 8085"`;

0 commit comments

Comments
 (0)