-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserver-react-render.jsx
152 lines (138 loc) · 6.72 KB
/
server-react-render.jsx
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
'use strict'
import React from 'react' // needed by render to string
import { renderToString } from 'react-dom/server'
import { JssProvider, SheetsRegistry, createGenerateId } from 'react-jss'
import cloneDeep from 'lodash/cloneDeep'
import { Helmet } from 'react-helmet'
const googleAnalytics = (props, req, res) =>
process.env.GOOGLE_ANALYTICS
? `<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=${process.env.GOOGLE_ANALYTICS}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${process.env.GOOGLE_ANALYTICS}');
</script>`
: ''
// extract meta tags from the web component
const metaTags = (props, req, res) =>
(props.iota &&
props.iota.webComponent &&
props.iota.webComponent.metaTags &&
props.iota.webComponent.metaTags.reduce((acc, meta) => acc + `<meta ${meta}>\n`, '')) ||
''
function serverReactRender(App, req, res, next) {
try {
const dev = process.env.NODE_ENV || 'development'
const user = req.cookies?.synuser
? typeof req.cookies?.synuser === 'string'
? JSON.parse(req.cookies.synuser)
: req.cookies.synuser
: undefined
const props = Object.assign(
{
env: dev, // depricated should go away one day
path: req.path,
user,
notFound: req.notFound,
error: res.locals.error,
location: req.url, // may be used by for use by react-router
},
cloneDeep(req.reactProps)
)
const sheets = new SheetsRegistry()
const generateId = createGenerateId()
const body = renderToString(
<JssProvider registry={sheets} generateId={generateId}>
<App {...props} />
</JssProvider>
)
const helmet = Helmet.renderStatic()
// figure out if browsers supports ES6 or not.
const ifES6 = () =>
props.browserConfig &&
((props.browserConfig.browser.name == 'chrome' && props.browserConfig.browser.version[0] >= 54) ||
(props.browserConfig.browser.name == 'safari' && props.browserConfig.browser.version[0] >= 11) ||
(props.browserConfig.browser.name == 'opera' && props.browserConfig.browser.version[0] >= 41) ||
(props.browserConfig.browser.name == 'firefox' && props.browserConfig.browser.version[0] >= 50) ||
(props.browserConfig.browser.name == 'edge' && props.browserConfig.browser.version[0] >= 15))
? (logger.info('index browser supports ES6'), '')
: (logger.info('index browser does not support ES6'), '')
// add google analitics code if env is set - usually only set in production
const ifLoadSockets = () =>
!(
req.hostname.startsWith('cc2020') || // host is the CDN
req.hostname.startsWith('undebate-stage1') || // host is stage-1 for testing
(dev === 'production' &&
props.iota &&
props.iota.webComponent &&
props.iota.webComponent.participants &&
!props.iota.webComponent.participants.human)
)
return res.send(
`<!doctype html>
<html ${helmet.htmlAttributes.toString()}>
<head>
${
helmet.title.toString() === '<title data-react-helmet="true"></title>'
? `<title>${(props.iota && props.iota.subject) || 'Candidate Conversations'}</title>`
: helmet.title.toString()
}
<meta httpEquiv='X-UA-Compatible' content='IE=edge'/>
<meta name='viewport' content='width=device-width, maximum-scale=1.0, initial-scale=1.0' />
<meta charSet="UTF-8"/>
${helmet.meta.toString()}
<link rel='icon' type='image.png' href='/assets/images/favicon-16x16.png' sizes='16x16'/>
<link rel='icon' type='image/png' href='/assets/images/favicon-32x32.png' sizes='32x32'/>
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/apple-touch-icon.png" />
<link rel="manifest" href="/assets/images/site.webmanifest"/>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
${helmet.link.toString()}
<meta name="theme-color" content="#ffffff"/>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style type="text/css">
${sheets.toString()}
</style>
<script>window.reactProps=${JSON.stringify(props) + ''}</script>
<script>window.env="${props.env}"</script>
<script src="https://kit.fontawesome.com/7258b64f3b.js" crossorigin="anonymous" async></script>
${serverReactRender.head.reduce(
(str, h) =>
str +
((str && '\n') || '') +
(typeof h === 'string' ? h : typeof h === 'function' ? h(props, req, res) : ''),
''
)}
<script>if(!window.process) window.process={}; if(!window.process.env) window.process.env={}; Object.assign(window.process.env, ${JSON.stringify(
(() => {
const browserEnv =
typeof window === 'undefined' &&
(process.env.BROWSER_ENV || '')
.split(',')
.reduce((env, key) => (key && (env[key] = process.env[key]), env), {})
if (browserEnv && !browserEnv.NODE_ENV) browserEnv.NODE_ENV = 'development'
return browserEnv
})()
)})</script>
${helmet.script.toString()}
</head>
<body style="margin: 0; padding: 0" ${helmet.bodyAttributes.toString()}>
<div id="synapp">${body}</div>
${ifES6()}
${ifLoadSockets() ? '<script src="/socket.io/socket.io.js" ></script>' : ''}
<script src='/assets/webpack/main.js' ></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
</body>
</html>`
)
} catch (error) {
logger.info('server-react-render failed', req.path)
next(error)
}
}
serverReactRender.head = []
serverReactRender.head.push(googleAnalytics)
serverReactRender.head.push(metaTags)
export default serverReactRender