-
Notifications
You must be signed in to change notification settings - Fork 10
/
ssr-renderer.tsx
111 lines (95 loc) · 3.48 KB
/
ssr-renderer.tsx
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
import React from 'react';
import { matchRoutes } from 'react-router-config';
import { renderToString } from 'react-dom/server';
const XmlEntities = require('html-entities').XmlEntities;
const xmlEntities = new XmlEntities();
import { generateNumberFromTimestamp } from '../../base/utilities/file';
import { isProductionMode } from '../../base/utilities/debug';
import i18n from '../../client/localization/i18n';
import { logger } from '../../base/utilities/logger';
/**
* Server side renderer utility class
*/
export class ServerSideRenderer {
/**
* Constructor
* @param bundleFilePath builde file path of webpack
*/
constructor(public bundleFilePath: string) {
}
/**
* Render component on server side
* @param req Express request object
* @param res Express response object
* @param ejsName ejs filename
* @param ejsOptions ejs options
* @param component container component
* @param cssGenerator css generator
*/
public render(req: any, res: any, ejsName: string, ejsOptions: any, store: any, component: (req, store, i18n) => any, cssGenerator?: () => string) {
try {
const protocol = (process.env.PROTOCOL || req.protocol);
let host = process.env.HOST || req.headers.host;
const lng = req.language;
logger.debug(`Request locale: ${lng}`);
const i18nServer = i18n.cloneInstance();
i18nServer.changeLanguage(lng);
const html = renderToString(
<>
{component(req, store, i18nServer)}
</>
);
let config = ejsOptions.config !== undefined ? ejsOptions.config : {};
if (!isProductionMode()) {
const serverState = {
host: host,
protocol: protocol,
};
Object.assign(config, serverState);
}
const timeStamp = generateNumberFromTimestamp(__dirname + '/../../../build/public/js/' + this.bundleFilePath);
let option = {
html: html,
config: xmlEntities.encode(JSON.stringify(config)),
css: cssGenerator !== undefined ? cssGenerator() : '',
bundle: '/js/' + this.bundleFilePath + '?ver=' + timeStamp
};
Object.assign(ejsOptions, option);
res.render(ejsName, ejsOptions);
} catch (err) {
logger.error(err);
}
}
/**
* Use when need to set special initalState initialized by each component
* @param req Express request object
* @param res Express response object
* @param ejsName ejs filename
* @param ejsOptions ejs options
* @param component container component
* @param routes route
* @param cssGenerator css generator
*/
public renderWithInitialProps(req: any, res: any, ejsName: string, ejsOptions: any, store, component: (req, store, i18n) => any, routes, cssGenerator?: () => string) {
const protocol = (process.env.PROTOCOL || req.protocol);
const host = process.env.HOST || req.headers.host;
const branch = matchRoutes(routes, req.baseUrl + req.url);
const promises = branch.map(({ route }) => {
let getInitialProps = route.component.getInitialProps;
return getInitialProps instanceof Function ? getInitialProps({
protocol: protocol,
host: host,
store: store,
req: req,
env: process.env
}) : Promise.resolve(undefined);
});
return Promise.all(promises).then((data) => {
let option = {
initialState: JSON.stringify(data),
};
Object.assign(option, ejsOptions);
this.render(req, res, ejsName, ejsOptions, store, component, cssGenerator);
});
}
}