-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
server.jsx
94 lines (77 loc) · 2.54 KB
/
server.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
import { FastRender } from 'meteor/communitypackages:fast-render';
import { Headers, Request } from 'meteor/fetch';
import React, { StrictMode } from 'react';
import { Helmet } from 'react-helmet';
import { createRoutesFromElements } from 'react-router-dom';
import { StaticRouterProvider, createStaticHandler, createStaticRouter } from 'react-router-dom/server';
import { renderToString } from 'react-dom/server';
import AbortController from 'abort-controller';
import { isAppUrl } from './helpers';
// This import just silences warnings from the check-npm-versions package because the
// import above has /server at the end and meteor won't bundle the package.json file for these.
import 'react-dom';
import './version-check';
const helmetTags = [
'base',
'meta',
'link',
'script',
'style',
'title',
'noscript',
];
export const renderWithSSR = (routes, { renderTarget = 'react-target' } = {}) => {
if (!Array.isArray(routes)) {
routes = createRoutesFromElements(routes);
}
const handler = createStaticHandler(routes);
FastRender.onPageLoad(async sink => {
if (!isAppUrl(sink.request)) {
return;
}
const fetchRequest = createFetchRequest(sink);
const context = await handler.query(fetchRequest);
const router = createStaticRouter(
handler.dataRoutes,
context,
);
const AppJSX = <StrictMode><StaticRouterProvider router={router} context={context} /></StrictMode>;
const renderedString = renderToString(AppJSX);
sink.renderIntoElementById(renderTarget, renderedString);
const helmet = Helmet.renderStatic();
helmetTags.forEach(tag => {
sink.appendToHead(helmet[tag].toString());
});
});
};
function createFetchRequest (sink) {
const sinkHeaders = sink.getHeaders();
const url = sink.request.url;
const headers = new Headers();
for (const [key, values] of Object.entries(sinkHeaders)) {
if (values) {
if (Array.isArray(values)) {
for (const value of values) {
headers.append(key, value);
}
} else {
headers.set(key, values);
}
}
}
const controller = new AbortController();
const init = {
method: 'GET',
headers,
signal: controller.signal,
};
const baseUrl = getBaseUrlFromHeaders(sinkHeaders);
const fullUrl = `${baseUrl}${url.pathname || ''}`;
const newUrl = new URL(fullUrl);
return new Request(newUrl, init);
};
const getBaseUrlFromHeaders = headers => {
const protocol = headers['x-forwarded-proto'];
const { host } = headers;
return `${protocol ? `${protocol}:` : ''}//${host}`;
};