Skip to content

Commit 87350f4

Browse files
Jasper De Moordevongovett
authored andcommitted
User friendly server errors and automatic port switching (#164)
* more userfriendly server errors and automatically asign free port if port is busy * cleanup code a lil * fix typo * remove unused import * minor improvements * change double quotes into single quotes * lil cleanup & restructuring * bugfixes
1 parent dc52638 commit 87350f4

7 files changed

Lines changed: 55 additions & 13 deletions

File tree

bin/cli.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ if (!args[2] || !program.commands.some(c => c.name() === args[2])) {
8181

8282
program.parse(args);
8383

84-
function bundle(main, command) {
84+
async function bundle(main, command) {
8585
// Require bundler here so the help command is fast
8686
const Bundler = require('../');
8787

@@ -94,7 +94,7 @@ function bundle(main, command) {
9494
const bundler = new Bundler(main, command);
9595

9696
if (command.name() === 'serve') {
97-
const server = bundler.serve(command.port || 1234);
97+
const server = await bundler.serve(command.port || 1234);
9898
if (command.open) {
9999
require('opn')(`http://localhost:${server.address().port}`);
100100
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"chokidar": "^1.7.0",
1919
"commander": "^2.11.0",
2020
"cssnano": "^3.10.0",
21+
"get-port": "^3.2.0",
2122
"glob": "^7.1.2",
2223
"htmlnano": "^0.1.6",
2324
"is-url": "^1.2.2",

src/Bundler.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const {EventEmitter} = require('events');
1313
const Logger = require('./Logger');
1414
const PackagerRegistry = require('./packagers');
1515
const localRequire = require('./utils/localRequire');
16+
const customErrors = require('./utils/customErrors');
1617

1718
/**
1819
* The Bundler is the main entry point. It resolves and loads assets,
@@ -452,12 +453,9 @@ class Bundler extends EventEmitter {
452453
return Server.middleware(this);
453454
}
454455

455-
serve(port = 1234) {
456-
this.logger.persistent(
457-
'Server running at ' + this.logger.chalk.cyan(`http://localhost:${port}`)
458-
);
456+
async serve(port = 1234) {
459457
this.bundle();
460-
return Server.serve(this, port);
458+
return await Server.serve(this, port);
461459
}
462460
}
463461

src/Server.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ const http = require('http');
22
const path = require('path');
33
const url = require('url');
44
const serveStatic = require('serve-static');
5+
const getPort = require('get-port');
6+
const serverErrors = require('./utils/customErrors').serverErrors;
57

68
function middleware(bundler) {
79
const serve = serveStatic(bundler.options.outDir, {index: false});
@@ -54,8 +56,29 @@ function middleware(bundler) {
5456
};
5557
}
5658

57-
function serve(bundler, port) {
58-
return http.createServer(middleware(bundler)).listen(port);
59+
async function serve(bundler, port) {
60+
let freePort = await getPort({port});
61+
let server = http.createServer(middleware(bundler)).listen(freePort);
62+
63+
server.on('error', err => {
64+
bundler.logger.error(new Error(serverErrors(err, server.address().port)));
65+
});
66+
67+
server.once('listening', connection => {
68+
let addon =
69+
server.address().port !== port
70+
? `- ${bundler.logger.chalk.red(
71+
`configured port ${port} could not be used.`
72+
)}`
73+
: '';
74+
bundler.logger.persistent(
75+
`Server running at ${bundler.logger.chalk.cyan(
76+
`http://localhost:${server.address().port}`
77+
)} ${addon}\n`
78+
);
79+
});
80+
81+
return server;
5982
}
6083

6184
exports.middleware = middleware;

src/utils/customErrors.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
let serverErrorList = {
2+
EACCES: "You don't have access to bind the server to port {port}.",
3+
EADDRINUSE: 'There is already a process listening on port {port}.'
4+
};
5+
6+
function serverErrors(err, port) {
7+
let desc = serverErrorList[err.code].replace(/{port}/g, port);
8+
if (!desc) {
9+
desc = `Error: ${
10+
err.code
11+
} occurred while setting up server on port ${port}.`;
12+
}
13+
return desc;
14+
}
15+
16+
module.exports.serverErrors = serverErrors;

test/server.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ describe('server', function() {
3131

3232
it('should serve files', async function() {
3333
let b = bundler(__dirname + '/integration/commonjs/index.js');
34-
server = b.serve(0);
34+
server = await b.serve(0);
3535

3636
let data = await get('/dist/index.js');
3737
assert.equal(data, fs.readFileSync(__dirname + '/dist/index.js', 'utf8'));
3838
});
3939

4040
it('should serve a default page if the main bundle is an HTML asset', async function() {
4141
let b = bundler(__dirname + '/integration/html/index.html');
42-
server = b.serve(0);
42+
server = await b.serve(0);
4343

4444
let data = await get('/');
4545
assert.equal(data, fs.readFileSync(__dirname + '/dist/index.html', 'utf8'));
@@ -50,7 +50,7 @@ describe('server', function() {
5050

5151
it('should serve a 404 if the file does not exist', async function() {
5252
let b = bundler(__dirname + '/integration/commonjs/index.js');
53-
server = b.serve(0);
53+
server = await b.serve(0);
5454

5555
let threw = false;
5656
try {
@@ -64,7 +64,7 @@ describe('server', function() {
6464

6565
it('should serve a 500 if the bundler errored', async function() {
6666
let b = bundler(__dirname + '/integration/html/index.html');
67-
server = b.serve(0);
67+
server = await b.serve(0);
6868

6969
b.errored = true;
7070

yarn.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,10 @@ get-own-enumerable-property-symbols@^2.0.1:
19001900
version "2.0.1"
19011901
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b"
19021902

1903+
get-port@^3.2.0:
1904+
version "3.2.0"
1905+
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
1906+
19031907
get-stdin@^4.0.1:
19041908
version "4.0.1"
19051909
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"

0 commit comments

Comments
 (0)