Next.js
Next.js 빌드에서 페이지가 누락된 경험
Next.js 빌드 후 특정 페이지가 없다고 하면, 빌드 로그를 먼저 자세히 확인해야 한다. 빌드 경고나 에러가 숨어 있을 수 있다.
Next.js로 블로그를 만들었는데, 빌드는 성공했다고 하는데 특정 페이지가 없다고 한다. 이런 상황은 보통 빌드 로그에 힌트가 있다.
빌드 로그를 전체로 보기
먼저 빌드 로그를 끝까지 본다.
# 빌드 실행
npm run build 2>&1 | tee build.log
# 로그 파일 검토
cat build.log | grep -E 'warning|error|skipped'
# 특정 페이지의 빌드 결과만 보기
grep "pages/blog" build.log
Next.js는 대부분의 경고를 화면에 출력하지 않는다. 로그 파일을 저장해서 봐야 한다.
페이지 파일이 실제로 있는지 확인하기
# 소스 파일 확인
find src/pages -name "*.tsx" | sort
find src/app -name "*.tsx" | sort
# 빌드된 파일 확인
ls -la .next/server/pages/
ls -la .next/static/
# 특정 페이지가 없다면?
ls -la .next/server/pages/blog/
빌드 후 .next 디렉토리에 파일이 없다면, 빌드 중에 건너뛰어졌다는 뜻이다.
getStaticProps 에러 확인하기
Next.js 스태틱 제너레이션에서 에러가 나면 그 페이지는 빌드되지 않을 수 있다.
# pages/blog/[slug].tsx
export async function getStaticPaths() {
const posts = await fetchPosts();
return {
paths: posts.map(post => ({
params: { slug: post.slug }
})),
fallback: false // 빌드되지 않은 경로는 404
};
}
// fetchPosts에서 에러가 나면 빌드가 실패한다
데이터 소스(API, 데이터베이스)가 빌드 시간에 접근 불가능하면 페이지 생성이 실패한다.
ISR 또는 동적 렌더링으로 바꾸기
getStaticProps로 빌드 시간에 모든 데이터를 fetch하는 대신, ISR이나 동적 렌더링을 쓸 수 있다.
// getStaticProps 대신 getServerSideProps (매 요청마다 렌더링)
export async function getServerSideProps(context) {
const post = await fetchPost(context.params.slug);
return {
props: { post },
revalidate: 3600 // 1시간마다 재검증
};
}
// 또는 App Router의 동적 렌더링
export default async function Page({ params }) {
const post = await fetchPost(params.slug);
return <Article post={post} />;
}
이렇게 하면 빌드 중에 모든 페이지를 미리 생성할 필요가 없다.
빌드 로그에서 에러 찾기
# 특정 문자열 검색
grep -i "failed\|error\|cannot" build.log
# 또는 less로 대화형 검색
less build.log
# 다음 'failed' 검색: /failed
# 에러 주변 문맥까지 보기
grep -B 2 -A 2 "Error:" build.log
환경 변수 확인하기
빌드 중에 필요한 환경 변수가 없으면 에러가 날 수도 있다.
# 빌드 시 환경 변수 확인
echo $API_URL
echo $DATABASE_URL
# .env.local에 있는가?
cat .env.local | grep API
# 빌드 시간에 필요한 변수를 .env.local에 추가
echo "API_URL=https://api.example.com" >> .env.local
npm run build
동적 라우트 경로 확인하기
동적 라우트[slug]로 페이지를 만들었을 때, getStaticPaths에서 반환한 경로만 빌드된다.
// 만약 getStaticPaths에서 이것을 반환했다면
return {
paths: [
{ params: { slug: 'first-post' } },
{ params: { slug: 'second-post' } },
],
fallback: false // 다른 경로는 404
};
// 그러면 'third-post' 페이지는 빌드되지 않는다
블로그 글이 늘어날 때마다 getStaticPaths를 수동으로 업데이트해야 하는데, 이걸 빠뜨릴 수 있다.
빌드 캐시 삭제하고 다시
.next 디렉토리의 캐시 때문에 실제로 다시 빌드되지 않을 수도 있다.
# 캐시 삭제
rm -rf .next
# 다시 빌드
npm run build
# 빌드 로그 확인
앞으로의 예방법
- 빌드 로그를 항상 전체로 저장하고 검토하기
- getStaticPaths에서 에러 처리 추가
- 데이터 소스가 빌드 시간에 접근 가능한지 확인
- 필요시 ISR이나 동적 렌더링으로 전환
- 새로운 페이지를 추가했을 때 getStaticPaths도 업데이트했는지 확인