Skip to content

Commit

Permalink
Merge pull request #90 from softeerbootcamp4th/feat/90-admin-cicd
Browse files Browse the repository at this point in the history
[build] 어드민 페이지 기본 세팅
  • Loading branch information
darkdulgi authored Aug 12, 2024
2 parents 5a6389d + 38093c3 commit eee17cb
Show file tree
Hide file tree
Showing 44 changed files with 389 additions and 77 deletions.
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

0 comments on commit eee17cb

Please sign in to comment.