
프로젝트 리팩토링 중,
Vite 프로젝트에서 Top-level await 에러를 만난 사례이다.
에러메세지)
[vite:esbuild-transpile] Transform failed with 1 error:
assets/index-!~{001}~.js:56784:15: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
결론) 아래의 모듈을 설치해서 해결했다.
npm i vite-plugin-top-level-await
문제가 된 코드는 아래의 코드다.
export const docRef = await getDocs(collection(db, "handshake"))
위의 코드처럼, async 함수의 스코프 내부에서 동작하지 않고, 모듈의 최상단에서 await 키워드를 활용해 비동기 함수를 처리하는 개념을 Top-level await라 한다.
이 개념이 표준이 되기 이전에도 dev모드에서는 정상작동했으나 공식적인 표준으로 인정받은 시점은 ES2022 부터이다.
Top-level await 키워드가 사용된 모듈 자체가 비동기 스코프가 된다.나는 firebase의 공식문서를 따라 handshake용 코드를 작성하고, 테스트를 위해 빌드를 하다가 이러한 문제를 발견했다. 그렇기에 경우에 따라 다음과 같이 4가지 방안이 있을 것이다.
- EsBuild과정에서 발생한 문제이므로, vite의 빌드 설정을 커스텀한다.
- vite5.0과 같이 최신버전의 빌더에서는 지원할 것으로 추측하고, 공식문서를 확인한 뒤 vite 버전을 업그레이드를 한다.
- Top-level await를 사용하지 않고 async-await 구문을 사용한다.
- ✅ 적절한 플러그인을 사용한다.
1.방법은 stackoverflow에서 찾은 방안이고, 해당 방안을 사용했음에도 제대로 동작하지 않았다.
// vite.config.ts
export default defineConfig({
plugins: [react()],
base: '/',
esbuild : {
supported: {
'top-level-await': true
}
}
})
2.방법은 단순히 구문 하나를 적용하기 위해 감수해야 하는 예기치 못한 오류들을 고려할 때, 당장은 Pass
3.방법을 적용해서 다음과 같은 코드를 작성했다.
// async-await 구문
export const docRef = async () => {
const res = await getDocs(collection(db, "handshake"))
return res.docs.forEach((doc) => {
console.log(doc.data());
})
}
useEffect(() => {
console.log(docRef())
}, [])
// Top-level await 구문
export const docRef = await getDocs(collection(db, "handshake"))
useEffect(() => {
console.log(docRef)
docRef.forEach((doc) => {
console.log(doc.data());
});
}, []);
작성하고 보니, 코드 줄에는 크게 차이가 없으나, 1)firebase 공식문서를 계속해서 참고해서 프로젝트를 개선할 것, 2)향후 custom hook 등을 만들어 프로젝트를 개선할 예정인 점을 고려할 때 다른 방안이 필요할 것으로 추측했다.
✅ 결국 4.방법을 선택해서 문제를 해결한다! 이미 잘 작성된 플러그인을 가져와 추가하면 간단히 해결된다. 이 방법은 추후에 모듈이 너무 많아져서 빌드 용량이 다소 커지게 되다면 또 다른 문제가 될 수 있다.
1)소규모 프로젝트인 점, 2)이번 프로젝트가 vite의 모듈번들러 최적화가 목적이 아닌 점을 고려할 때 빠르게 문제를 해결하고 넘어가는 것이 좋을 것 같아 이 방법을 택했다.