Bleeding edge

prerendering page "/" ReferenceError: window is not defined 본문

Javascript

prerendering page "/" ReferenceError: window is not defined

codevil 2023. 10. 21. 14:30

문제점

이번에 React native와 Nextjs를 이용하여 앱을 만들고 있었다. 전역 상태로 window를 사용하는 함수가 있었고,  SSR 에서 window 객체가 없는 순간에 에러가 나오기 때문에 빌드 에러가 발생한다.

에러 메세지

일반적인 window is not defined 해결 방법

처음부터 끝까지 내가 작성한 함수의 경우 window is not defined는 그 함수가 시작하는 지점 혹은, window 객체를 사용하는 지점에서 다음과 같이 return을 하면 문제가 없다.

if(typeof window === 'undefined') return

하지만 이번에 문제를 일으킨 함수같은 경우 heic2any라는 라이브러리라서 import를 하는 순간 window is not defined가 발생한다.

 

첫 번째 시도: DynamicProvider

문제가 생긴 지점에서 window type을 이용하는 방법이 통하지 않는다는 것을 확인하고, 전역 함수의 프로바이더를 Dyanmic import 하였다.

//before
import { ImageFetchProvider } from '@/contexts/ImageFetchContext';


//after
const DynamicProviderWithoutSSR = dynamic(
  async () => {
    const ImageFetch = await import('@/contexts/ImageFetchContext');
    return ImageFetch.ImageFetchProvider;
  },
  { ssr: false }
);

이 방법이 어느 정도는 유효했던 것은 처음에는 Context를 공유하는 모든 페이지에서 prerendering 에러가 발생했었지만, 이 방법을 사용하니 ImageFetchProvider만 사용한 페이지만 prerendering 에러가 발생했다. 

 

두 번째 시도: Dynamic import

before

import heic2any from 'heic2any';

export async function convertToJPG(file: File): Promise<Blob> {
  let imageFile: Blob = file;
  if (file.type === 'image/jpeg') return imageFile;
  if (file.type === 'image/heic' || file.type === 'image/heif') {
    const result = heic2any({
      blob: file,
      toType: 'image/png',
      quality: 1,
    });
...
  }
...
}

after

  if (file.type === 'image/heic' || file.type === 'image/heif') {
    const heic2any = (await import('heic2any')).default;
    const result = heic2any({
      blob: file,
      toType: 'image/png',
      quality: 1,
    });

    if (Array.isArray(result)) {
      throw new Error('Expected a single image, but got multiple images.');
    }
    imageFile = result;
  }

이 방법을 사용하니 prerendering 해결되었다. 물론, heic2any에서는 blob 객체와 blob을 반환하기 때문에 이를 원하는 값이 나오도록 수정하였지만..

 

후기

nodejs와 javascript가 혼재하는 nextjs에서는 window is not defined는 생각보다 자주 만나는 에러다. 항상 localstorage나 다른 내가만든 함수에서만 만나는 에러여서 조건문 하나로 해결하고 넘어갔었다. 하지만 이번에 라이브러리 내부에서 window를 사용하는 것을 보고, 새로운 해결책을 찾아내면서 다음에 같은 에러가 발생하면 이런 방식으로도 해결 할 수 있거나를 생각 할 수 있어서 좋았다.

개발도 게임과 비슷하다. 모르면 맞아야한다(그 폭력적인게 아니라 모르면 당해야한다..?)