Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[build] 어드민 페이지 기본 세팅 #90

Merged
merged 7 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions admin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="소프티어 부트캠프 4기-팀 어썸 오렌지의 IONIQ 5 어드민 페이지입니다." />
<title>Awesome Orange - Admin</title>
</head>
<body>
<div id="root"><!--hydrate_root--></div>
<script type="module" src="/src/adminPage/main-client.jsx"></script>
</body>
</html>
97 changes: 97 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { build } from "vite";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import process from "node:process";
import { readFile, writeFile, rm, mkdir } from "node:fs/promises";
import config from "./vite.config.js";

const __dirname = fileURLToPath(new URL('.', import.meta.url));
const mode = process.argv[2] ?? "main";
const toAbsolute = (p) => resolve(__dirname, p);

const buildConfig = {
main: {
clientEntry: "index.html",
sourceDir: "mainPage",
ssgEntry: "main-server.jsx"
},
admin: {
clientEntry: "admin.html",
sourceDir: "adminPage",
ssgEntry: "main-server.jsx",
url: [
"index",
"events",
"events/create",
"login",
"events/[id]",
"comments",
"comments/[id]"
]
},
}

async function processBuild(mode) {
await Promise.all([buildClient(mode), buildSSG(mode)]);
await injectSSGToHtml(mode);
}

async function buildClient(mode) {
await build({
...config,
build: {
rollupOptions: {
input: {
entry: buildConfig[mode].clientEntry
},
output: {
dir: `dist/${mode}`
}
}
}
});
await rm(toAbsolute(`dist/${mode}/mockServiceWorker.js`));
}

function buildSSG(mode) {
return build({
...config,
build: {
ssr: true,
rollupOptions: {
input: {
entry: `src/${buildConfig[mode].sourceDir}/${buildConfig[mode].ssgEntry}`
},
output: {
dir: `dist-ssg/${mode}`
}
}
}
});
}

async function injectSSGToHtml(mode) {
console.log("--ssg result--");
const {default: render} = await import(`./dist-ssg/${mode}/entry.js`);
const template = await readFile(`dist/${mode}/${buildConfig[mode].clientEntry}`, "utf-8");

const urlEntryPoint = buildConfig[mode].url ?? ["index"];

const promises = urlEntryPoint.map( async (path)=>{
const absolutePath = toAbsolute(`dist/${mode}/${path}.html`);
try {
const html = template.replace("<!--hydrate_root-->", render(path));

const dir = dirname(absolutePath);
await mkdir(dir, { recursive: true });
await writeFile(absolutePath, html);
console.log(`pre-rendered : ${path}`);
} catch {
console.log(`pre-rendered failed : ${path}`);
}
} );
await Promise.allSettled(promises);
console.log("--successfully build completed!--");
}

processBuild(mode);
50 changes: 46 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
{
"name": "vite-project",
"name": "awesome-orange-project",
"private": true,
"version": "0.0.0",
"version": "0.5.0",
"type": "module",
"scripts": {
"dev": "vite --host",
"build": "vite build && npm run build:server && node prerender.js && rm dist/mockServiceWorker.js",
"build:client": "vite build",
"build:server": "vite build --ssr src/main-server.jsx --outDir dist-ssg",
"build": "node build.js main",
"build-admin": "node build.js admin",
"format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css}'",
"lint": "eslint . --ext js,jsx --max-warnings 0",
"lint-fix": "eslint . --ext js,jsx --fix",
"preview": "vite preview"
"preview": "vite preview --outDir dist/main",
"preview-admin": "vite preview --outDir dist/admin"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-lottie-player": "^2.1.0",
"react-router-dom": "^6.26.0",
"swiper": "^11.1.9",
"zustand": "^4.5.4"
},
Expand Down
26 changes: 0 additions & 26 deletions prerender.js

This file was deleted.

File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
23 changes: 23 additions & 0 deletions src/adminPage/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Route, Routes } from "react-router-dom";

function App() {
return (
<>
<Routes>
<Route
exact
path="/events/create"
element={<div>event 생성 화면</div>}
/>
<Route path="/events/:id" element={<div>event 보는 화면</div>} />
<Route path="/events" element={<div>이벤트 목록 화면</div>} />
<Route path="/comments/:id" element={<div>기대평 화면</div>} />
<Route path="/comments" element={<div>기대평 검색 화면</div>} />
<Route path="/login" element={<div>로그인 화면</div>} />
<Route path="/" element={<div>hello</div>} />
</Routes>
</>
);
}

export default App;
34 changes: 34 additions & 0 deletions src/adminPage/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@font-face {
font-family: "ds-digital";
src: url("/font/DS-DIGI.TTF") format("truetype");
font-display: swap;
}

@font-face {
font-family: "hdsans";
src: url("/font/HyundaiSansTextKROTFBold.otf") format("opentype");
font-weight: bold;
font-display: swap;
}

@font-face {
font-family: "hdsans";
src: url("/font/HyundaiSansTextKROTFMedium.otf") format("opentype");
font-weight: medium;
font-display: swap;
}

@layer base {
body {
font-family: "hdsans";
}
body.scrollLocked {
position: fixed;
width: 100%;
overflow-y: scroll;
}
}
37 changes: 37 additions & 0 deletions src/adminPage/main-client.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { StrictMode } from "react";
import { createRoot, hydrateRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.jsx";
import "./index.css";

const $root = document.getElementById("root");

if (import.meta.env.DEV) {
// 개발 시
const enableMocking = async function () {
// 실서버와 연동시 //return;의 주석 지워서 테스트해주세요
// return;
const worker = (await import("./mock.js")).default;
await worker.start({ onUnhandledRequest: "bypass" });
};
enableMocking().then(() => {
const root = createRoot($root);
root.render(
<StrictMode>
<BrowserRouter basename="/admin">
<App />
</BrowserRouter>
</StrictMode>,
);
});
} else {
// 배포 시
hydrateRoot(
$root,
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
);
}
30 changes: 30 additions & 0 deletions src/adminPage/main-server.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { StrictMode } from "react";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router-dom/server";
import App from "./App.jsx";

export default function render(url) {
const path = url === "index" ? "/" : `/${url}`;
const nye = renderToString(
<StrictMode>
<StaticRouter location={path}>
<App />
</StaticRouter>
</StrictMode>,
);
return nye;
}

/**
* 우리의 메인 컴포넌트를 문자열로 렌더링하는 함수를 반환합니다.
*
* 향후 페이지가 추가된다면,
*
* import SecondPage from "./SecondPage.jsx";
*
* export default function render(url) {
* // 여기에서 url에 따라 분기처리를 하면 됩니다.
* }
*
* 현재로서는 단일 페이지이므로 render 함수 내에 분기처리를 하지 않습니다.
*/
6 changes: 6 additions & 0 deletions src/adminPage/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { setupWorker } from "msw/browser";

// mocking은 기본적으로 각 feature 폴더 내의 mock.js로 정의합니다.
// 새로운 feature의 mocking을 추가하셨으면, mock.js의 setupWorker 내부 함수에 인자를 spread 연산자를 이용해 추가해주세요.
// 예시 : export default setupWorker(...authHandler, ...questionHandler, ...articleHandler);
export default setupWorker();
3 changes: 2 additions & 1 deletion src/common/constants.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const EVENT_ID = "0";
export const TOKEN_ID = "AWESOME_ORANGE_ACCESS_TOKEN";
export const SERVICE_TOKEN_ID = "AWESOME_ORANGE_ACCESS_TOKEN";
export const ADMIN_TOKEN_ID = "AWESOME_ORANGE_ADMIN_ACCESS_TOKEN";
Loading