forked from ReactTraining/react-stdio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
127 lines (107 loc) · 3.23 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
'use strict'
const path = require('path')
const invariant = require('invariant')
const EventStream = require('event-stream')
const JSONStream = require('JSONStream')
const ReactDOMServer = require('react-dom/server')
const React = require('react')
function getDefaultExports(moduleID) {
// Clear the require cache, in case the file was
// changed since the server was started.
const cacheKey = require.resolve(moduleID)
delete require.cache[cacheKey]
const moduleExports = require(moduleID)
// Return exports.default if using ES2015 modules.
if (moduleExports && moduleExports.default)
return moduleExports.default
return moduleExports
}
function renderToStaticMarkup(element, callback) {
callback(null, ReactDOMServer.renderToStaticMarkup(element))
}
function renderToString(element, callback) {
callback(null, ReactDOMServer.renderToString(element))
}
function handleRequest(workingDir, request, callback) {
const componentPath = request.component
const renderMethod = request.render
const props = request.props
invariant(
componentPath != null,
'Missing { component } in request'
)
let render
if (renderMethod == null || renderMethod === 'renderToString') {
render = renderToString
} else if (renderMethod === 'renderToStaticMarkup') {
render = renderToStaticMarkup
} else {
const methodFile = path.resolve(workingDir, renderMethod)
try {
render = getDefaultExports(methodFile)
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND')
process.stderr.write(error.stack + '\n')
}
}
invariant(
typeof render === 'function',
'Cannot load render method: %s',
renderMethod
)
const componentFile = path.resolve(workingDir, componentPath)
let component
try {
component = getDefaultExports(componentFile)
} catch (error) {
if (error.code !== 'MODULE_NOT_FOUND')
process.stderr.write(error.stack + '\n')
}
invariant(
component != null,
'Cannot load component: %s',
componentPath
)
render(
React.createElement(component, props),
callback
)
}
function createRequestHandler(workingDir) {
return function (request, callback) {
try {
handleRequest(workingDir, request, function (error, html) {
if (error) {
callback(error)
} else if (typeof html !== 'string') {
// Crash the server process.
callback(new Error('Render method must return a string'))
} else {
callback(null, JSON.stringify({ html: html }))
}
})
} catch (error) {
callback(null, JSON.stringify({ error: error.message }))
}
}
}
// Redirect stdout to stderr, but save a reference so we can
// still write to stdout.
const stdout = process.stdout
Object.defineProperty(process, 'stdout', {
configurable: true,
enumerable: true,
value: process.stderr
})
// Ensure console.log knows about the new stdout.
const Console = require('console').Console
Object.defineProperty(global, 'console', {
configurable: true,
enumerable: true,
value: new Console(process.stdout, process.stderr)
})
// Read JSON blobs from stdin, pipe output to stdout.
process.stdin
.pipe(JSONStream.parse())
.pipe(EventStream.map(createRequestHandler(process.cwd())))
.pipe(stdout)