2025.1.15 수요일의 공부기록
Next.js 프로젝트를 Vercel을 통해 배포하려고 시도하면서 몇 가지 문제를 직면했고, 이를 해결하는 과정을 정리했다.
export 제한으로 인한 컴파일 오류Next.js의 app 디렉토리 구조에서는 페이지 파일에서 특정 필드만 export로 내보내는 것이 허용된다.
metadata, generateMetadata, default 등 Next.js가 정의한 필드 외의 임의의 변수를 export로 내보내면 컴파일 오류가 발생한다.
예를 들어, 아래 코드에서 API_URL을 export로 내보냈기 때문에 문제가 발생했다.
import Movie from "../components/movie";
import styles from "../../styles/home.module.css";
export const metadata = {
title: "Home",
};
export const API_URL = "https://nomad-movies.nomadcoders.workers.dev/movies"; // 문제 발생
async function getMovies() {
return fetch(API_URL).then((response) => response.json());
}
export default async function HomePage() {
const movies = await getMovies();
return (
<div className={styles.container}>
{movies.map((movie) => (
<Movie
key={movie.id}
id={movie.id}
poster_path={movie.poster_path}
title={movie.title}
/>
))}
</div>
);
}
export하려고 했기 때문에 발생한 컴파일 오류.API_URL과 같은 값을 .env 파일로 관리하고, 이를 코드에서 process.env.NEXT_PUBLIC_* 형식으로 참조하도록 변경했다.
import Movie from "../components/movie";
import styles from "../../styles/home.module.css";
export const metadata = {
title: "Home",
};
async function getMovies() {
return fetch(process.env.NEXT_PUBLIC_API_URL).then((response) =>
response.json()
);
}
export default async function HomePage() {
const movies = await getMovies();
return (
<div className={styles.container}>
{movies.map((movie) => (
<Movie
key={movie.id}
id={movie.id}
poster_path={movie.poster_path}
title={movie.title}
/>
))}
</div>
);
}
.env 파일 예시NEXT_PUBLIC_API_URL=https://nomad-movies.nomadcoders.workers.dev/movies
Next.js에서 props.params의 타입이 개발자가 정의한 IParams 타입과 일치하지 않는다는 오류가 발생했다.
구체적으로, params는 Next.js 내부적으로 Promise 객체로 처리되는데, 개발자는 이를 일반 객체로 정의했기 때문에 타입 오류가 발생했다.

interface IParams {
params: { id: string };
}
export async function generateMetadata({ params: { id } }: IParams) {
const movie = await getMovie(id);
return {
title: movie.title,
};
}
export default async function MovieDetail({ params }: IParams) {
const { id } = await params;
return (
<div>
<Suspense fallback={<h1>Loading movie info</h1>}>
<MovieInfo id={id} />
</Suspense>
<Suspense fallback={<h1>Loading movie videos</h1>}>
<MovieVideos id={id} />
</Suspense>
</div>
);
}
props.params를 Promise 객체로 처리하지만, 개발자는 이를 단순 객체로 정의했다.Promise<{ id: string }> 형식)과 불일치하여 오류가 발생했다.params를 Promise로 처리props.params가 Promise 객체임을 명확히 하고, 이를 await로 처리하도록 코드를 수정했다.
import { Suspense } from "react";
import MovieInfo, { getMovie } from "../../../components/movie-info";
import MovieVideos from "../../../components/movie-videos";
type IParams = Promise<{ id: string }>;
export async function generateMetadata(props: { params: IParams }) {
const params = await props.params;
const id = params.id;
const movie = await getMovie(id);
return {
title: movie.title,
};
}
export default async function MovieDetail(props: { params: IParams }) {
const params = await props.params;
const id = params.id;
return (
<div>
<Suspense fallback={<h1>Loading movie info</h1>}>
<MovieInfo id={id} />
</Suspense>
<Suspense fallback={<h1>Loading movie videos</h1>}>
<MovieVideos id={id} />
</Suspense>
</div>
);
}
.env 파일을 사용하여 export 문제를 해결.params의 타입을 Promise로 정의하고, await로 처리하여 타입 불일치 문제를 해결.git push를 통해 Vercel에서 자동 배포를 실행했다.Next.js의 app 디렉토리 제한
export하면 오류가 발생한다.타입 정의 중요성
params와 같은 기본 제공 값의 타입을 정확히 이해하고 처리해야 한다.