본문 바로가기
Issue

Next.js) Error: Element type is invalid. Received a promise that resolves to: [object Promise]. Lazy element type must resolve to a class or function.

by 박채니 2024. 4. 12.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.

 

상황

NextJS를 이용해서 Token Counter 기능을 tiktoken으로 구현하고 싶었다.

 

tiktoken github를 보면 알 수 있듯, NextJS에서 tiktoken을 사용하려면 아래와 같은 설정이 필요하다.

https://github.com/dqbd/tiktoken?tab=readme-ov-file#nextjs

 

GitHub - dqbd/tiktoken: JS port and JS/WASM bindings for openai/tiktoken

JS port and JS/WASM bindings for openai/tiktoken. Contribute to dqbd/tiktoken development by creating an account on GitHub.

github.com

 

// next.config.json
const config = {
  webpack(config, { isServer, dev }) {
    config.experiments = {
      asyncWebAssembly: true,
      layers: true,
    };

    return config;
  },
};

 

위 설정을 한 후 tiktoken을 이용하여 Token Counter 로직을 짜고 run을 했더니.. 아래와 같은 오류가 발생하였다.

 

오류 메세지

Error: Element type is invalid. Received a promise that resolves to: [object Promise]. Lazy element type must resolve to a class or function.

 

오류 메세지를 서칭해본 결과 위와 같은 이유로 발생하는 오류라고 판단했다.

 

오류 해결 과정 (이라 쓰고 삽질 과정이라 읽는다.)

일단, 내가 tiktoken을 프로젝트에 적용시키기 전에 테스트로 생성한 Next 프로젝트에서는 정상작동 한 것을 보아 "use client"와 상관이 있다고 판단했다.

 

그렇다면, 왜? 왜 발생하는 걸까?

정말 많은 삽질과 시간을 쏟아부었는데, 정답은 webpack 설정에 있는듯 했다!

 

asyncWebAssembly: true,

 

위 설정에 대해서 파보았는데, 이는 tiktoken이 Python으로 이루어져있어서 WASM 처리 후 사용하기 위해 asyncWebAssembly을 설정한다는 사실을 알게 되었다.

원인이 여기에 있는듯해보였고, WASM이 뭔지 그리고 Lazy Loading이 뭔지 검색해보았다.

 

WASM (WebAssembly)

  • 최신 웹 브라우저에서 실행할 수 있는 새로운 유형의 코드
  • 여러 언어로 작성된 코드들을 네이티브에 가까운 속도로 웹으로 돌릴 수 있음
  • C/C++, Rust 등과 같은 언어를 WebAssembly로 컴파일하여 웹에서 실행 가능

참고 사이트

https://developer.mozilla.org/ko/docs/WebAssembly/Concepts

 

Lazy Loading

  • 경로를 렌더링하는데에 필요한 js 양을 줄여 애플리케이션 초기 로딩 성능 향상에 도움
    • 중요도가 떨어지는 요소들의 로딩을 우선적으로 시행하지 않으면서 웹페이지 로딩 퍼포먼스 최적화

참고 사이트

https://seo-tory.tistory.com/84

https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading

 

정확하진 않지만, Client Component에서 비동기 Element를 import 해서 사용하려고 하니 오류가 발생한듯 했다.

 

해결방법

// lazy loading을 위해 next/dynamic 사용
// 해당 컴포넌트는 필요해진 경우에만 로딩되므로 ssr: false 처리
const TokenCounter = dynamic(() => import("@/components/page/token-counter/TokenCounter"), {
    ssr: false,
});

 

next/dynamic을 사용하여 Lazy Loading 처리를 해주었더니, 해결되었다.

 

NextJS에서 Lazy Loading 구현 방법

1️⃣ next/dynamic

2️⃣ React.lazy() + Suspense

 

위 두 방법이 있는데, 1번 방식이 간편해보여서 1번 방식으로 해결했다.

 

 

일단 이리저리 서치하고 공부해서 오류를 해결하긴 했지만, 아직까지도 정확히 어떤 원인으로 오류가 발생했는지는 모르겠다..

NextJS에 대한 지식이 얕아서 그런 것 같기도 하다...! ㅎ