-
Notifications
You must be signed in to change notification settings - Fork 39
/
server.ts
91 lines (88 loc) · 3.52 KB
/
server.ts
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
import { createServer, IncomingMessage, ServerResponse } from 'http';
import { createFactory, version as reactVersion } from 'react';
import { renderToNodeStream, version as reactDomVersion } from 'react-dom/server';
import { createReadStream } from 'fs';
import App from './components/app';
import { fetchProps } from './props';
import { lookup } from './mime-types';
import { control } from './cache-control';
import {
faviconUrl,
stylesUrl,
browserUrl,
browserMapUrl,
propsUrl,
containerId,
} from './constants';
console.log('Server booting...');
const isProd = process.env.NODE_ENV === 'production';
console.log('Production optimization enabled? ', isProd);
const AppFactory = createFactory(App);
const PORT = process.env.PORT || 3007;
const suffix = isProd ? '.production.min.js' : '.development.js';
export default async function handler(req: IncomingMessage, res: ServerResponse) {
let { httpVersion, method, url } = req;
console.log(`${httpVersion} ${method} ${url}`);
if (!url || url === '/') {
url = 'index.html';
}
try {
if (url === 'index.html') {
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 1));
res.write(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${faviconUrl}" rel="icon" type="image/x-icon" />
<title>React Example</title>
<link rel="stylesheet" href="${stylesUrl}" />
</head>
<body>
<div id="${containerId}">`);
const stream = renderToNodeStream(AppFactory(fetchProps()));
stream.pipe(res, { end: false });
stream.on('end', () => {
res.end(`</div>
<script src="https://unpkg.com/react@${reactVersion}/umd/react${suffix}"></script>
<script src="https://unpkg.com/react-dom@${reactDomVersion}/umd/react-dom${suffix}"></script>
<script src="${browserUrl}"></script>
</body>
</html>`);
});
} else if (url === propsUrl) {
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 0));
res.end(JSON.stringify(fetchProps()));
} else if (url === stylesUrl) {
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 7));
const file = `./src/${url}`;
createReadStream(file).pipe(res);
} else if (url === browserUrl || url === browserMapUrl) {
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 7));
const file = `./dist${url}`;
createReadStream(file).pipe(res);
} else {
url = 'notfound.txt';
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 0));
res.statusCode = 404;
res.end('404 Not Found');
}
} catch (e) {
console.error(e);
url = 'notfound.txt';
res.setHeader('Content-Type', lookup(url));
res.setHeader('Cache-Control', control(isProd, 0));
res.statusCode = 500;
res.end('500 Internal Error');
}
}
if (require.main === module) {
createServer(handler).listen(PORT, () => {
console.log(`Listening on ${PORT}...`);
});
}