1 |
|
2 |
|
3 | import "@babel/polyfill";
|
4 |
|
5 | import React, { ReactNode} from "react";
|
6 | import ReactDOMServer from "react-dom/server";
|
7 | import express from "express";
|
8 | import serverless from "serverless-http";
|
9 |
|
10 |
|
11 | import { ServerStyleSheet } from 'styled-components';
|
12 | import { matchPath } from 'react-router';
|
13 | import helmet from 'react-helmet';
|
14 | import {createServerApp} from "./routed-app";
|
15 |
|
16 | import Types from '../src/types';
|
17 | import { extractObject, INFRASTRUCTURE_MODES, loadConfigurationFromModule } from '../src/libs/loader';
|
18 |
|
19 |
|
20 | export const getClientFilename = (name: string): string => {
|
21 | return name+".bundle.js";
|
22 | }
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | const createServer = (assetsDir, resolvedAssetsPath, isomorphicId) => {
|
28 |
|
29 |
|
30 | const app = express();
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | app.use('/'+assetsDir, express.static(resolvedAssetsPath));
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | const isoConfig = loadConfigurationFromModule(require('__CONFIG_FILE_PATH__'), INFRASTRUCTURE_MODES.RUNTIME);
|
41 |
|
42 |
|
43 |
|
44 | const isoApp = extractObject(
|
45 | isoConfig,
|
46 | Types.INFRASTRUCTURE_TYPE_CONFIGURATION,
|
47 | isomorphicId
|
48 | )
|
49 |
|
50 | isoApp.middlewares.map(mw => app.use(mw.callback));
|
51 |
|
52 |
|
53 |
|
54 | isoApp.webApps
|
55 |
|
56 | .map(clientApp => {
|
57 |
|
58 | const serveMiddleware = (req, res, next) => serve(req, res, next, clientApp, assetsDir);
|
59 | const routes = clientApp.routes.filter(route => route.middlewares !== undefined && route.middlewares.length > 0);
|
60 |
|
61 | if (clientApp.method.toUpperCase() == "GET") {
|
62 |
|
63 | app.get(clientApp.path, ...clientApp.middlewares.map(mw => mw.callback));
|
64 | routes.forEach(route => app.get(route.path, ...route.middlewares.map(mw => mw.callback)));
|
65 | app.get(clientApp.path, serveMiddleware);
|
66 |
|
67 | } else if (clientApp.method.toUpperCase() == "POST") {
|
68 |
|
69 | app.post(clientApp.path, ...clientApp.middlewares.map(mw => mw.callback));
|
70 | routes.forEach(route => app.post(route.path, ...route.middlewares.map(mw => mw.callback)));
|
71 | app.post(clientApp.path, serveMiddleware);
|
72 |
|
73 | } else if (clientApp.method.toUpperCase() == "PUT") {
|
74 |
|
75 | app.put(clientApp.path, ...clientApp.middlewares.map(mw => mw.callback));
|
76 | routes.forEach(route => app.put(route.path, ...route.middlewares.map(mw => mw.callback)));
|
77 | app.put(clientApp.path, serveMiddleware);
|
78 |
|
79 | } else if (clientApp.method.toUpperCase() == "DELETE") {
|
80 |
|
81 | app.delete(clientApp.path, ...clientApp.middlewares.map(mw => mw.callback));
|
82 | routes.forEach(route => app.delete(route.path, ...route.middlewares.map(mw => mw.callback)));
|
83 | app.delete(clientApp.path, serveMiddleware);
|
84 |
|
85 | }
|
86 |
|
87 | return clientApp;
|
88 | });
|
89 |
|
90 |
|
91 | return app;
|
92 | };
|
93 |
|
94 |
|
95 | async function serve (req, res, next, clientApp, assetsDir) {
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | let context: any = {};
|
103 |
|
104 |
|
105 | const basename = getBasename();
|
106 |
|
107 |
|
108 | const sheet = new ServerStyleSheet();
|
109 |
|
110 |
|
111 | const parsedUrl = req.url.indexOf("?") >= 0 ? req.url.substring(0, req.url.indexOf("?")) : req.url;
|
112 | console.log("parsedUrl: ", parsedUrl);
|
113 |
|
114 |
|
115 |
|
116 | var foundPath = undefined;
|
117 |
|
118 |
|
119 |
|
120 | let matchResult = clientApp.routes.find(
|
121 | ({ path, exact }) => {
|
122 | foundPath = matchPath(parsedUrl,
|
123 | {
|
124 | path,
|
125 | exact,
|
126 | strict: false
|
127 | }
|
128 | )
|
129 | return foundPath
|
130 | }) || {};
|
131 | let { path } = matchResult;
|
132 |
|
133 | console.log("found: ", foundPath);
|
134 | console.log("params: ", foundPath ? foundPath.params : "---");
|
135 |
|
136 | const routePath = foundPath ? (
|
137 | foundPath.path.indexOf("/:") > 0 ?
|
138 | foundPath.path.substring(0, foundPath.path.indexOf("/:")) :
|
139 | foundPath.path
|
140 | ) : "";
|
141 |
|
142 | console.log("routePath: ", routePath);
|
143 |
|
144 |
|
145 |
|
146 |
|
147 | const connectWithDataLayer = clientApp.dataLayer !== undefined ?
|
148 | clientApp.dataLayer.type({infrastructureMode: "component"}).connectWithDataLayer :
|
149 | async function (app) {
|
150 | console.log("default dummy data layer")
|
151 | return {connectedApp: app, getState: () => ""};
|
152 | };
|
153 |
|
154 |
|
155 | await connectWithDataLayer(
|
156 | createServerApp(
|
157 | clientApp.routes,
|
158 | clientApp.redirects,
|
159 | basename,
|
160 | req.url,
|
161 | context, req)
|
162 | ).then(({connectedApp, getState}) => {
|
163 |
|
164 | console.log("resolved...")
|
165 |
|
166 |
|
167 | const htmlData = ReactDOMServer.renderToString(sheet.collectStyles(connectedApp));
|
168 |
|
169 |
|
170 | const styles = sheet.getStyleTags();
|
171 |
|
172 |
|
173 | const helmetData = helmet.renderStatic();
|
174 |
|
175 |
|
176 | res.status(200).send(
|
177 | renderHtmlPage(htmlData, styles, getState(), helmetData, basename, routePath, clientApp, assetsDir)
|
178 | ).end();
|
179 | });
|
180 |
|
181 |
|
182 | }
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | function renderHtmlPage(html, styles, preloadedState, helmet, basename, routePath, clientApp, assetsDir) {
|
225 |
|
226 | console.log(preloadedState);
|
227 | const path = require('path');
|
228 |
|
229 | const calcBase = () => {
|
230 | return path.join(basename, routePath);
|
231 | }
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 | console.log("calcBase: ", calcBase());
|
239 |
|
240 | return `<!doctype html>
|
241 | <html>
|
242 | <head>
|
243 | <meta charset="utf-8" />
|
244 | ${helmet.title.toString()}
|
245 | ${helmet.meta.toString()}
|
246 | ${helmet.link.toString()}
|
247 | ${styles}
|
248 | <style>
|
249 | body {
|
250 | display: block;
|
251 | margin: 0px;
|
252 | }
|
253 | </style>
|
254 | </head>
|
255 | <body>
|
256 | <div id="root">${html.trim()}</div>
|
257 | <script>
|
258 | ${preloadedState}
|
259 | window.__BASENAME__ = "${basename}";
|
260 | </script>
|
261 | <script>
|
262 | var loadscript = document.createElement('script');
|
263 | function getPath() {
|
264 | console.log( window.location.pathname);
|
265 | const basePath = ${basename !== "/" ? "window.location.pathname.startsWith(\""+basename+"\") ? \"\": \"/\" " : "\"\"" };
|
266 | const routePath= "${routePath !== "/" ? routePath : ""}";
|
267 | const pre = window.location.pathname.startsWith(basePath+routePath+"/") ? ".." : "";
|
268 | return pre+"${path.join(basename, assetsDir, getClientFilename(clientApp.id))}";
|
269 |
|
270 | }
|
271 |
|
272 | loadscript.setAttribute('src',getPath());
|
273 | document.body.appendChild(loadscript);
|
274 | </script>
|
275 |
|
276 | </body>
|
277 | </html>`
|
278 | }
|
279 |
|
280 | const getBasename = () => {
|
281 | return process.env.STAGE_PATH !== undefined && process.env.STAGE_PATH !== "undefined" ?
|
282 | "/"+process.env.STAGE_PATH : "/";
|
283 | };
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | export default serverless(createServer(__ASSETS_PATH__, __RESOLVED_ASSETS_PATH__, __ISOMORPHIC_ID__)); |
\ | No newline at end of file |