서버 컴포넌트에서 조회하는 유저 정보를 build 과정에서 불러오지 못하는 에러가 발생했다. 처음 코드에서는 try-catch문 안에 accessToken을 넣었는데 이를 불러오지 못해서 발생한 문제로 파악된다.
Next.js의 cookies()는 서버 컴포넌트에서만 사용할 수 있는 API인데, getUsers 함수가 비동기 함수(async)로 정의되어 있기 때문에 빌드 과정에서 오류가 발생했다.
const getUsers = async () => {
try {
const cookieStore = cookies();
const accessToken = cookieStore.get("accessToken")?.value;
const response = await fetch(`${API_URL}/users/me`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
next: { tags: ["users"] },
});
if (!response.ok) {
return null;
}
return response.json();
} catch (error) {
console.error("유저 정보 가져오기 실패", error);
return null;
}
};
비동기 블록(try 내부)에서 cookies()를 호출하는 것이 아닌, 동기적으로 실행되는 함수에서 호출하였다. 즉, cookies()는 비동기 await 코드보다 먼저 실행되므로 Next.js가 이를 서버 환경에서 동기적으로 실행한다. Next.js가 cookies()를 클라이언트에서 실행하려고 시도하지 않으므로 빌드 타임 오류가 사라졌다.
import { cookies } from "next/headers";
import API_URL from "@/constants/config";
import Image from "next/image";
import Link from "next/link";
import s from "./Header.module.scss";
import classNames from "classnames/bind";
import User from "@/components/Layout/Header/User";
import SearchBar from "@/components/Layout/Header/SearchBar";
import Alarm from "@/components/Alarm/Alarm";
import { customFetch } from "@/utils/customFetch";
export const cx = classNames.bind(s);
const getUsers = async () => {
const cookieStore = cookies();
const accessToken = cookieStore.get("accessToken")?.value;
try {
const response = await fetch(`${API_URL}/users/me`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
next: { tags: ["users"] },
});
if (!response.ok) {
return null;
}
return response.json();
} catch (error) {
console.error("유저 정보 가져오기 실패", error);
return null;
}
};
const Header = async () => {
const users = await getUsers();
return (
<header className={s.header}>
<section className={cx("headerContainer", "container")}>
<Link href={"/"} className={s.logo}>
<Image src={"/images/logo.svg"} fill alt="TRAVEL MAKER" />
</Link>
<div className={s.search}>
<SearchBar />
</div>
{!users ? (
<div className={s.loginOff}>
<Link href={"/login"}>로그인</Link>
<Link href={"/signup"}>회원가입</Link>
</div>
) : (
<>
<User users={users} />
</>
)}
</section>
</header>
);
};
export default Header;