/
Server.js
154 lines (136 loc) Β· 4.26 KB
/
Server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
const http = require('http');
const https = require('https');
const serveStatic = require('serve-static');
const getPort = require('get-port');
const serverErrors = require('./utils/customErrors').serverErrors;
const generateCertificate = require('./utils/generateCertificate');
const getCertificate = require('./utils/getCertificate');
const prettyError = require('./utils/prettyError');
const AnsiToHtml = require('ansi-to-html');
const logger = require('./Logger');
const path = require('path');
const url = require('url');
const ansiToHtml = new AnsiToHtml({newline: true});
serveStatic.mime.define({
'application/wasm': ['wasm']
});
function setHeaders(res) {
enableCors(res);
}
function enableCors(res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Methods',
'GET, HEAD, PUT, PATCH, POST, DELETE'
);
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Content-Type'
);
}
function middleware(bundler) {
const serve = serveStatic(bundler.options.outDir, {
index: false,
redirect: false,
setHeaders: setHeaders
});
return function(req, res, next) {
// Wait for the bundler to finish bundling if needed
if (bundler.pending) {
bundler.once('bundled', respond);
} else {
respond();
}
function respond() {
let {pathname} = url.parse(req.url);
if (bundler.error) {
return send500(bundler.error);
} else if (
!pathname.startsWith(bundler.options.publicURL) ||
path.extname(pathname) === ''
) {
// If the URL doesn't start with the public path, or the URL doesn't
// have a file extension, send the main HTML bundle.
return sendIndex();
} else {
// Otherwise, serve the file from the dist folder
req.url = pathname.slice(bundler.options.publicURL.length);
return serve(req, res, send404);
}
}
function sendIndex() {
// If the main asset is an HTML file, serve it
if (bundler.mainBundle.type === 'html') {
req.url = `/${path.basename(bundler.mainBundle.name)}`;
serve(req, res, send404);
} else {
send404();
}
}
function send500(error) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.writeHead(500);
let errorMesssge = '<h1>π¨ Build Error</h1>';
if (process.env.NODE_ENV === 'production') {
errorMesssge += '<p><b>Check the console for details.</b></p>';
} else {
const {message, stack} = prettyError(error, {color: true});
errorMesssge += `<p><b>${message}</b></p>`;
if (stack) {
errorMesssge += `<div style="background: black; padding: 1rem;">${ansiToHtml.toHtml(
stack
)}</div>`;
}
}
res.end(
[
`<!doctype html>`,
`<head><title>π¨ Build Error</title></head>`,
`<body style="font-family: monospace; white-space: pre;">${errorMesssge}</body>`
].join('')
);
}
function send404() {
if (next) {
return next();
}
res.writeHead(404);
res.end();
}
};
}
async function serve(bundler, port, useHTTPS = false) {
let handler = middleware(bundler);
let server;
if (!useHTTPS) {
server = http.createServer(handler);
} else if (typeof useHTTPS === 'boolean') {
server = https.createServer(generateCertificate(bundler.options), handler);
} else {
server = https.createServer(await getCertificate(useHTTPS), handler);
}
let freePort = await getPort({port});
server.listen(freePort);
return new Promise((resolve, reject) => {
server.on('error', err => {
logger.error(new Error(serverErrors(err, server.address().port)));
reject(err);
});
server.once('listening', () => {
let addon =
server.address().port !== port
? `- ${logger.chalk.yellow(
`configured port ${port} could not be used.`
)}`
: '';
logger.persistent(
`Server running at ${logger.chalk.cyan(
`${useHTTPS ? 'https' : 'http'}://localhost:${server.address().port}`
)} ${addon}`
);
resolve(server);
});
});
}
exports.middleware = middleware;
exports.serve = serve;