UNPKG

3.35 kBJavaScriptView Raw
1/*
2 Copyright © 2018 Andrew Powell
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 The above copyright notice and this permission notice shall be
9 included in all copies or substantial portions of this Source Code Form.
10*/
11const url = require('url');
12const { createServer } = require('http');
13
14const open = require('open');
15
16const { getBuiltins } = require('./middleware');
17const { setupRoutes } = require('./routes');
18
19const select = (options, callback) => {
20 /* eslint-disable global-require */
21 const types = {
22 http: createServer,
23 https: require('https').createServer,
24 http2: require('http2').createServer,
25 http2Secure: require('http2').createSecureServer
26 };
27 const { http2, https } = options;
28 let server;
29 let secure = false;
30
31 if (http2) {
32 if (http2 === true) {
33 server = types.http2({}, callback);
34 } else if (http2.cert || http2.pfx) {
35 secure = true;
36 server = types.http2Secure(http2, callback);
37 } else {
38 server = types.http2(http2, callback);
39 }
40 } else if (https) {
41 secure = true;
42 server = types.https(https === true ? {} : https, callback);
43 } else {
44 server = types.http(callback);
45 }
46
47 return { secure, server };
48};
49
50const start = async function start() {
51 if (this.listening) {
52 return;
53 }
54
55 const { app } = this;
56 const { host, middleware, port, waitForBuild } = this.options;
57 const builtins = getBuiltins(app, this.options);
58
59 this.options.host = await host;
60 this.options.port = await port;
61
62 if (waitForBuild) {
63 app.use(async (ctx, next) => {
64 await this.state.compiling;
65 await next();
66 });
67 }
68
69 // allow users to add and manipulate middleware in the config
70 await middleware(app, builtins);
71
72 // call each of the builtin middleware. methods are once'd so this has no ill-effects.
73 for (const fn of Object.values(builtins)) {
74 if (!fn.skip) {
75 fn();
76 }
77 }
78
79 setupRoutes.bind(this)();
80
81 const { secure, server } = select(this.options, app.callback());
82 const emitter = this;
83
84 this.options.secure = secure;
85
86 server.listen({ host: this.options.host, port: this.options.port });
87
88 // wait for the server to fully spin up before asking it for details
89 await {
90 then(r, f) {
91 server.on('listening', () => {
92 emitter.emit('listening', server);
93 r();
94 });
95 server.on('error', f);
96 }
97 };
98
99 this.listening = true;
100
101 const protocol = secure ? 'https' : 'http';
102 const address = server.address();
103
104 address.hostname = address.address;
105
106 // fix #131 - server address reported as 127.0.0.1 for localhost
107 if (address.hostname !== this.options.host && this.options.host === 'localhost') {
108 address.hostname = this.options.host;
109 }
110
111 // we set this so the client can use the actual hostname of the server. sometimes the net
112 // will mutate the actual hostname value (e.g. :: -> [::])
113 this.options.address = url.format(address);
114
115 const uri = `${protocol}://${this.options.address}`;
116
117 this.log.info('Server Listening on:', uri);
118
119 this.once('done', () => {
120 if (this.options.open) {
121 open(uri, this.options.open === true ? {} : this.options.open);
122 }
123 });
124};
125
126module.exports = { start };