문제 1. 서버 컴포넌트에서 원하는 함수가 매번 실행되지 않음
현상
- 노트 페이지에 진입할 때
shuffle()로 리스트를 섞으려고 했음 - 하지만 매번 같은 순서의 리스트를 보여줌
@/app/note/page.tsx
const Notes = async () => {
const data = getPostData("note");
return (
<div className="flex flex-col">
<StaggerGridList count={data.length}>
{shuffle(data).map(async ({ slug, metadata: { title }, content }) => {
const exceprt = await highlightMarkdown(getExcerpt(content));
return (
<SquareLink
key={slug}
title={title}
href={`/note/${slug}`}
excerpt={exceprt}
/>
);
})}
</StaggerGridList>
</div>
);
};
export default Notes;
원인
Notes컴포넌트는 파일 시스템을 통한 정적 데이터만 사용하고 있음- Next.js는 정적 데이터를 다루는 컴포넌트는 정적 사이트로 생성함
- SSG 페이지는 동적으로 렌더링되지 않음
조치
@/app/note/page.tsx
export const dynamic = "force-dynamic";
// .. 이하 코드 동일
강제로 동적 렌더링
문제 2. 배포된 서버에서 파일 시스템에 접근하지 못하는 이슈
- 현상: 배포 이후 노트 페이지에서 500 에러 발생
- 원인: 파일 시스템에 접근하지 못함
- 조치:
process.cwd()를 사용하여 안정적인 경로 접근이 가능하도록 수정
문제 3. 동적 렌더링으로 인한 지연
현상
force-dynamic옵션을 적용하여 동적 렌더링 강제하도록 하니까 노트 페이지 진입할 때 약간의 지연 발생
원인
export const dynamic = "force-dynamic";사용하여 페이지를 항상 동적 렌더링(SSR)하도록 강제- 페이지 요청 시마다 서버에서
getPostData("note")실행하여 파일 시스템에서 게시글 데이터 읽음 - 읽어온 데이터에 대해
shuffle,getExcerpt,highlightMarkdown연산을 서버 렌더링 과정 중 수행 - 단순 순서 섞기를 위해 매 요청마다 파일 시스템 접근 및 전체 데이터 처리 로직을 서버에서 처리
조치
export const dynamic = "force-dynamic";제거하여 컴포넌트를 다시 SSG로 생성- 서버 컴포넌트 (
page.tsx)와 클라이언트 컴포넌트 (NoteListClient.tsx)로 분리 getPostData실행 및 데이터 전처리(getExcerpt,highlightMarkdown)를 서버에서 수행- 처리된 데이터 배열 (
processedNotes)을 클라이언트 컴포넌트에props로 전달 shuffle은 클라이언트 컴포넌트에서 수행
const Notes = async () => {
const data = getPostData("note");
const processedNotes = await Promise.all(
data.map(async ({ slug, metadata: { title }, content }) => {
const excerpt = await highlightMarkdown(getExcerpt(content));
return { slug, title, excerpt };
}),
);
return (
<div className="flex flex-col">
<NoteList notes={processedNotes} />
</div>
);
};
export default Notes;
후기
- 빌드 과정에서 많은 일을 처리해보자.
- 가급적 정적 사이트를 만들어보자.
- 무분별한
force-dynamics사용은 조심하자. - 런타임에서 파일 시스템 접근이 필요할 때 파일 경로 잘 설정하자.
- 서버에서 할 일과 클라이언트에서 할 일을 잘 구분하고 설계하자.