webpack-plugin-serve
Version:
A Development Server in a Webpack Plugin
127 lines (99 loc) • 3.35 kB
JavaScript
/*
Copyright © 2018 Andrew Powell
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of this Source Code Form.
*/
const url = require('url');
const { createServer } = require('http');
const open = require('open');
const { getBuiltins } = require('./middleware');
const { setupRoutes } = require('./routes');
const select = (options, callback) => {
/* eslint-disable global-require */
const types = {
http: createServer,
https: require('https').createServer,
http2: require('http2').createServer,
http2Secure: require('http2').createSecureServer
};
const { http2, https } = options;
let server;
let secure = false;
if (http2) {
if (http2 === true) {
server = types.http2({}, callback);
} else if (http2.cert || http2.pfx) {
secure = true;
server = types.http2Secure(http2, callback);
} else {
server = types.http2(http2, callback);
}
} else if (https) {
secure = true;
server = types.https(https === true ? {} : https, callback);
} else {
server = types.http(callback);
}
return { secure, server };
};
const start = async function start() {
if (this.listening) {
return;
}
const { app } = this;
const { host, middleware, port, waitForBuild } = this.options;
const builtins = getBuiltins(app, this.options);
this.options.host = await host;
this.options.port = await port;
if (waitForBuild) {
app.use(async (ctx, next) => {
await this.state.compiling;
await next();
});
}
// allow users to add and manipulate middleware in the config
await middleware(app, builtins);
// call each of the builtin middleware. methods are once'd so this has no ill-effects.
for (const fn of Object.values(builtins)) {
if (!fn.skip) {
fn();
}
}
setupRoutes.bind(this)();
const { secure, server } = select(this.options, app.callback());
const emitter = this;
this.options.secure = secure;
server.listen({ host: this.options.host, port: this.options.port });
// wait for the server to fully spin up before asking it for details
await {
then(r, f) {
server.on('listening', () => {
emitter.emit('listening', server);
r();
});
server.on('error', f);
}
};
this.listening = true;
const protocol = secure ? 'https' : 'http';
const address = server.address();
address.hostname = address.address;
// fix #131 - server address reported as 127.0.0.1 for localhost
if (address.hostname !== this.options.host && this.options.host === 'localhost') {
address.hostname = this.options.host;
}
// we set this so the client can use the actual hostname of the server. sometimes the net
// will mutate the actual hostname value (e.g. :: -> [::])
this.options.address = url.format(address);
const uri = `${protocol}://${this.options.address}`;
this.log.info('Server Listening on:', uri);
this.once('done', () => {
if (this.options.open) {
open(uri, this.options.open === true ? {} : this.options.open);
}
});
};
module.exports = { start };