|
1 | | -import { renderToString } from "react-dom/server"; |
2 | | -import { createElement } from "react"; |
3 | 1 | import fs from "fs"; |
| 2 | +import path from "node:path"; |
| 3 | +import { createServer } from "vite"; |
4 | 4 |
|
5 | | -async function generateStaticSite() { |
6 | | - // HTML 템플릿 읽기 |
7 | | - const template = fs.readFileSync("../../dist/react/index.html", "utf-8"); |
| 5 | +const vite = await createServer({ |
| 6 | + server: { middlewareMode: true }, |
| 7 | + appType: "custom", |
| 8 | +}); |
8 | 9 |
|
9 | | - // 어플리케이션 렌더링하기 |
10 | | - const appHtml = renderToString(createElement("div", null, "안녕하세요")); |
| 10 | +const { mswServer } = await vite.ssrLoadModule("./src/mocks/node.ts"); |
| 11 | +mswServer.listen({ |
| 12 | + onUnhandledRequest: "bypass", |
| 13 | +}); |
11 | 14 |
|
12 | | - // 결과 HTML 생성하기 |
13 | | - const result = template.replace("<!--app-html-->", appHtml); |
14 | | - fs.writeFileSync("../../dist/react/index.html", result); |
| 15 | +const { render } = await vite.ssrLoadModule("./src/main-server.tsx"); |
| 16 | + |
| 17 | +const joinDist = (...pathnames) => path.join("../../dist/react", ...pathnames); |
| 18 | + |
| 19 | +const template = fs.readFileSync(joinDist("/index.html"), "utf-8"); |
| 20 | + |
| 21 | +async function generateStaticSite(pathname) { |
| 22 | + const fullPathname = pathname.endsWith(".html") ? joinDist(pathname) : joinDist(pathname, "/index.html"); |
| 23 | + const parsedPath = path.parse(fullPathname); |
| 24 | + |
| 25 | + const rendered = await render(pathname, {}); |
| 26 | + |
| 27 | + const html = template |
| 28 | + .replace(`<!--app-head-->`, rendered.head ?? "") |
| 29 | + .replace(`<!--app-html-->`, rendered.html ?? "") |
| 30 | + .replace( |
| 31 | + `<!-- app-data -->`, |
| 32 | + `<script>window.__INITIAL_DATA__ = ${JSON.stringify(rendered.__INITIAL_DATA__)};</script>`, |
| 33 | + ); |
| 34 | + |
| 35 | + if (!fs.existsSync(parsedPath.dir)) { |
| 36 | + fs.mkdirSync(parsedPath.dir, { recursive: true }); |
| 37 | + } |
| 38 | + |
| 39 | + fs.writeFileSync(fullPathname, html); |
15 | 40 | } |
16 | 41 |
|
17 | | -// 실행 |
18 | | -generateStaticSite(); |
| 42 | +// 404 생성 |
| 43 | +await generateStaticSite("/404.html"); |
| 44 | + |
| 45 | +// 홈 생성 |
| 46 | +await generateStaticSite("/"); |
| 47 | + |
| 48 | +// 상세페이지 생성 |
| 49 | +const { getProducts } = await vite.ssrLoadModule("./src/api/productApi.ts"); |
| 50 | +const { products } = await getProducts(); |
| 51 | +await Promise.all(products.map(async ({ productId }) => await generateStaticSite(`/product/${productId}/`))); |
| 52 | + |
| 53 | +mswServer.close(); |
| 54 | +vite.close(); |
0 commit comments