Skip to content

Commit 2db0b46

Browse files
committed
feat: 리액트 미들웨어 서버 개발
1 parent e64776d commit 2db0b46

File tree

1 file changed

+60
-18
lines changed

1 file changed

+60
-18
lines changed

packages/react/server.js

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,71 @@
11
import express from "express";
2-
import { renderToString } from "react-dom/server";
3-
import { createElement } from "react";
2+
import fs from "fs";
43

54
const prod = process.env.NODE_ENV === "production";
65
const port = process.env.PORT || 5174;
76
const base = process.env.BASE || (prod ? "/front_6th_chapter4-1/react/" : "/");
87

98
const app = express();
109

11-
app.get("*all", (req, res) => {
12-
res.send(
13-
`
14-
<!DOCTYPE html>
15-
<html lang="en">
16-
<head>
17-
<meta charset="UTF-8" />
18-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
19-
<title>React SSR</title>
20-
</head>
21-
<body>
22-
<div id="app">${renderToString(createElement("div", null, "안녕하세요"))}</div>
23-
</body>
24-
</html>
25-
`.trim(),
26-
);
10+
const setupMiddlewares = async () => {
11+
if (!prod) {
12+
const { createServer } = await import("vite");
13+
const viteServer = await createServer({
14+
server: { middlewareMode: true },
15+
appType: "custom",
16+
base,
17+
});
18+
app.use(viteServer.middlewares);
19+
return viteServer;
20+
}
21+
const compression = (await import("compression")).default;
22+
const sirv = (await import("sirv")).default;
23+
24+
app.use(compression());
25+
app.use(base, sirv("./dist/react", { extensions: [] }));
26+
27+
return null;
28+
};
29+
30+
const viteServer = await setupMiddlewares();
31+
32+
const templateHtml = prod ? fs.readFileSync("./dist/react/index.html", "utf8") : "";
33+
34+
const get = {
35+
template: async (viteServer, url) => {
36+
if (prod) return templateHtml;
37+
38+
const rawHtml = fs.readFileSync("./index.html", "utf-8");
39+
const transformedHtml = await viteServer.transformIndexHtml(url, rawHtml);
40+
return transformedHtml;
41+
},
42+
render: async (viteServer) => {
43+
if (prod) return (await import("./dist/react-ssr/main-server.js")).render;
44+
return (await viteServer.ssrLoadModule("/src/main-server.tsx")).render;
45+
},
46+
};
47+
48+
app.get("*all", async (request, response) => {
49+
try {
50+
const url = request.originalUrl.replace(base, "");
51+
52+
const template = await get.template(viteServer, url);
53+
const render = await get.render(viteServer);
54+
const { head, html, initialData, status = 200 } = await render(url, request.query ?? {});
55+
56+
const initialDataScript = initialData
57+
? `<script>window.__INITIAL_DATA__=${JSON.stringify(initialData).replace(/</g, "\\u003c")}</script>`
58+
: "";
59+
60+
const finalHtml = template
61+
.replace(`<!--app-head-->`, head ?? "")
62+
.replace(`<!--app-html-->`, html ?? "")
63+
.replace("</head>", `${initialDataScript}</head>`);
64+
65+
response.status(status).set({ "Content-Type": "text/html" }).send(finalHtml);
66+
} catch (error) {
67+
response.status(500).end(error.stack);
68+
}
2769
});
2870

2971
// Start http server

0 commit comments

Comments
 (0)