
에러메세지
hook.js:608
./src/lib/constant.ts
The generated code contains 'async/await' because this module is using "topLevelAwait".
However, your target environment does not appear to support 'async/await'.
As a result, the code may not run as expected or may cause runtime errors.
(번역) 생성된 코드에는 'async/await'가 포함되어 있는데, 이 모듈은 "topLevelAwait"를 사용하고 있기 때문입니다.
그러나 대상 환경은 'async/await'를 지원하지 않는 것 같습니다.
그 결과, 코드가 예상대로 실행되지 않거나 런타임 오류가 발생할 수 있습니다.
./src/lib/constant.ts 경로의 버전 정보를 호출하는 비동기 함수로 보여진다.현재 프로젝트는
next-lol
├─ src
│ ├─ app
│ │ ├─ api
│ │ │ ├─ fetchData.ts
│ │ │ └─ rotation
│ │ │ └─ route.ts // route-handler
│ │ ├─ items
│ │ │ ├─ [id]
│ │ │ │ └─ page.tsx
│ │ │ └─ page.tsx
│ │ ├─ layout.tsx
│ │ ├─ page.tsx
│ │ └─ rotation
│ │ └─ page.tsx // CSR page
│ ├─ components
│ │ └─ Card.tsx
│ ├─ lib
│ │ ├─ constant.ts // warning 발생
│ └─ types
│ ├─ Champion.ts
│ ├─ ChampionRotation.ts
│ └─ Item.ts
...
위와 같은 구조를 사용하고 있는데,
rotation/page.tsx가 CSR방식으로 구현되었으나 VERSION정보를 비동기적으로 사용하고 있어서 문제가 되는 것으로 보인다.
물론 그것 뿐만 아니라 서버 컴포넌트에서 사용하는 비동기 함수를 가져다 쓴 것도 문제가 될 수 있을듯..
"use client";
import { useEffect, useState } from "react";
import Card from "@/components/Card";
import { VERSION } from "@/lib/constant";
import { Champion } from "@/types/Champion";
const Rotation = () => {
interface Dataset {
freeChampionIds: number[];
freeChampionIdsForNewPlayers: number[];
maxNewPlayerLevel: number;
}
const [dataset, setDataset] = useState<Dataset | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [champions, setChampions] = useState<Record<string, Champion>>({});
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch("/api/rotation").then((res) => res.json());
setDataset(response);
const resChampion = await fetch(
`https://ddragon.leagueoflegends.com/cdn/${VERSION}/data/ko_KR/champion.json`,
);
const allChampions = await resChampion.json();
const rotationChampions: Record<string, Champion> = {};
response.freeChampionIds.forEach((id: number) => {
const champKey = Object.keys(allChampions.data).find(
(key) => allChampions.data[key].key === String(id),
);
if (champKey) {
rotationChampions[champKey] = allChampions.data[champKey];
}
});
setChampions(rotationChampions);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
DOM요소를 반환하는 부분은 생략.
Client 컴포넌트로 선언을 해 두고, 비동기 함수들은 useEffect안에서 처리하고자 하였으나, 일단 첫번째로 문제가 되는 것은 VERSION.
import { getLatestVersion } from "@/app/api/fetchData";
export const VERSION = await getLatestVersion();
VERSION이라는 상수는 상수의 탈을 썼지만, 사실은 await getLatestVersion()을 실행시키는 것이므로 이 부분이 문제가 될 것이라고 예측할 수 있었다.
비동기 함수를 실행하고 있는 로직을 어떻게 바꾸면 버전 정보만을 상수로 전달하도록 바꿀 수 있을까?
빌드 타임이나 서버 사이드에서 비동기 함수를 실행, 그 결과값을 미리 받아서 클라이언트 컴포넌트에 전달하는 방식으로 바꿔야 한다.
만일 내가 구현하려는 rotation 페이지가 server component 안에 종속된다면, props로 내려주는 것이 비교적 간단했을 것 같다.
다만 현재 프로젝트 요구사항에서 rotation 페이지를 서버 컴포넌트에 넣어도 되는지는 명시되어 있지 않기 때문에, 최대한 CSR 방식을 유지하면서 최신 version 정보를 사용할 수 있도록 하기 위해서
아래와 같은 방법을 사용했다.
빌드 시점에 데이터를 가져와서 환경 변수에 주입
next.config.mjs파일 수정- 환경 변수로 주입하여 클라이언트와 서버 모두에서
process.env.NEXT_PUBLIC_변수명으로 사용 가능하도록 만들기
그럼 프로젝트가 빌드되는 시점에 getLatestVersion 함수를 실행시켜 최신 버전정보를 프로젝트 내에 환경변수로 공유할 수 있다.
데이터의 버전 정보 같은 경우에는, 실시간으로 변경되는 데이터가 아니므로 빌드시점에만 업데이트해 두어도 주요 로직에 영향이 없다고 판단하였다.
/** @type {import('next').NextConfig} */
// 최신 버전 정보 fetch 함수 정의
async function getLatestVersion() {
const res = await fetch(
"https://ddragon.leagueoflegends.com/api/versions.json",
);
const versions = await res.json();
return versions[0];
}
const version = await getLatestVersion(); // 함수 실행결과 할당
const nextConfig = {
images: {
// remotePatterns ...
},
env: {
NEXT_PUBLIC_VERSION: version, // 환경변수로 프로젝트에 공유
},
};
export default nextConfig;

이제 기존에 발생하던 img 경고 외에, topLevelAwait 사용에 대한 경고문은 사라진 것을 확인할 수 있다.
하지만 여전히 배포환경에서는 안된다.... 뭐가 문제일까 ㅠㅠ