TDD,E2E 개선, 미적용 스타일 개선
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
import type { Block, ProjectConfig } from "@/features/editor/state/editorStore";
|
||||
import { buildStaticHtml } from "@/features/export/buildStaticHtml";
|
||||
import { getCachedPublicProject } from "@/features/projects/publicCache";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
interface PageParams {
|
||||
// Next.js App Router 에서는 params 가 Promise 로 전달되므로
|
||||
// 서버 컴포넌트에서 사용하기 전에 await 로 한 번 풀어줘야 한다.
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
// /p/[slug] 공개 페이지
|
||||
// - slug 에 해당하는 Project 의 contentJson 을 불러와 buildStaticHtml 로 정적 HTML 을 생성한다.
|
||||
// - Export ZIP 에 포함되는 index.html 과 동일한 app-root DOM 구조를 사용해 렌더링한다.
|
||||
// - 인증 없이 접근 가능하며, 폼 제출은 /api/forms/submit 을 통해 정적 Export 와 동일하게 동작한다.
|
||||
export default async function PublicProjectPage({ params }: PageParams) {
|
||||
// Next 가 넘겨주는 params 는 Promise 이므로, 먼저 await 해서 slug 를 꺼낸다.
|
||||
const resolvedParams = await params;
|
||||
const slugRaw = resolvedParams.slug ?? "";
|
||||
const slug = slugRaw.toString().trim();
|
||||
|
||||
if (!slug) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
// 1차로 메모리 기반 퍼블릭 캐시에서 스냅샷을 조회한다.
|
||||
const cached = getCachedPublicProject(slug);
|
||||
|
||||
let blocks: Block[];
|
||||
let title: string;
|
||||
|
||||
if (cached) {
|
||||
blocks = cached.contentJson ?? [];
|
||||
title = cached.title ?? "";
|
||||
} else {
|
||||
const project = await prisma.project.findUnique({
|
||||
where: { slug },
|
||||
select: {
|
||||
title: true,
|
||||
slug: true,
|
||||
contentJson: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
blocks = (project.contentJson ?? []) as Block[];
|
||||
title = project.title;
|
||||
}
|
||||
|
||||
// Export index.html 과 동일한 규칙으로 ProjectConfig 를 구성한다.
|
||||
const projectConfig: ProjectConfig = {
|
||||
title,
|
||||
slug,
|
||||
canvasPreset: "full",
|
||||
canvasBgColorHex: "#020617",
|
||||
bodyBgColorHex: "#020617",
|
||||
} as ProjectConfig;
|
||||
|
||||
const fullHtml = buildStaticHtml(blocks, projectConfig);
|
||||
|
||||
// buildStaticHtml 이 생성한 index.html 에서 <main> ... </main> 블록만 추출해 렌더링한다.
|
||||
// 이렇게 하면 Export index.html 과 동일한 main/app-root DOM 구조를 재사용할 수 있다.
|
||||
const mainMatch = fullHtml.match(/<main[\s\S]*?<\/main>/);
|
||||
const mainHtml = mainMatch ? mainMatch[0] : "";
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: mainHtml }} />;
|
||||
}
|
||||
Reference in New Issue
Block a user