Vercel 배포 JS미실행

JeongChan·2025년 7월 23일

Troubleshooting

목록 보기
6/6
post-thumbnail

배포를 vercel로 진행하다가 겪은 에러에 대한 문서이다. 이 문제 말고도 여러문제가 있었지만 중요한 순서대로 문서를 작성해 보았다..

프로젝트 구조

형식: Next.js App Router 기반 모노레포

앱 경로: apps/web

특징: Supabase 연동, Sentry, PWA 포함


📌 로컬 Dev환경에서는 문제 없다가 배포가 되고 문제가 발생


1. 문제 개요

  • 오류 상황: Vercel을 통해 production 환경에 배포한 후 웹사이트를 열었을 때, JavaScript가 아예 실행되지 않음. React 컴포넌트에서 동작해야 할 인터랙션(버튼 클릭, 입력 등)이 모두 무응답 상태로 남아 있음. SSR로 초기 화면은 렌더링되나, 클라이언트 측 JS 실행이 완전히 중단됨.
  • 발생 배경: Sentry를 @sentry/nextjs 패키지를 통해 프로젝트에 통합하고 Replay 기능을 활성화한 뒤, 해당 문제가 발생하기 시작함. 로컬 개발 환경에서는 정상 작동했으나, Vercel에 배포 후 production 환경에서 JS가 작동하지 않음을 확인함.

2. 오류 코드 및 오류 메시지

  • 오류 코드: 없음 (HTTP 상태는 200 OK이나, JS 로딩 실패)
  • 오류 메시지 (브라우저 콘솔 로그):
    
    Uncaught Error: Multiple Sentry Session Replay instances are not supported
        at new rq (chunk-sentry.js:2:34885)
        at Object.rH (chunk-sentry.js:2:32411)
  • 관련 로그:
    
    chunk-app.js:1 Uncaught ReferenceError: window is not defined
    b2b66d86-1430f5fa6910f625.js:1 Multiple Sentry Session Replay instances are not supported

3. 원인 분석

  • 오류 원인:

    instrumentation.ts, instrumentation-client.ts, sentry.config.ts 파일이 모두 존재하고 각각에서 Sentry.init()을 실행하면서, Replay가 클라이언트에서 중복 초기화됨.

    Replay 기능은 브라우저에서 단 한 번만 초기화돼야 하는데, 이 중복 초기화로 인해 JavaScript 번들이 완전히 멈추는 치명적인 문제가 발생한 것.

  • 에러 로그 해석:

    • Multiple Sentry Session Replay instances are not supported: Replay는 싱글톤으로 동작해야 하며, 두 번 이상 초기화될 경우 예외를 던지고 JS 실행을 중단함.
    • ReferenceError: window is not defined: SSR 환경에서 Replay 관련 코드가 조건 없이 실행되면서 서버에서 window 참조 오류 발생.
  • 구조적 이해:

    • @sentry/nextjs는 Next.js App Router 기반 프로젝트에서 클라이언트와 서버 각각 따로 초기화해야 함.
    • Replay는 클라이언트에서만 동작하는 기능이며, 서버 환경(NEXT_RUNTIME=nodejs 또는 edge)에서는 절대 실행되면 안 됨.
    • Sentry의 instrumentation.tsinstrumentation-client.ts가 각각 잘 분리되어야 중복 없이 작동 가능.
  • ✅ Replay 기능이란?

    Sentry Replay는 사용자의 세션을 동영상처럼 기록해 오류가 발생했을 때 그 전후 UI 상태를 재현할 수 있도록 해준다. 사용자가 어떤 경로를 거쳐 문제를 만났는지 추적할 수 있어 버그 재현과 원인 파악에 매우 효과적이다.

    하지만 이 기능은 브라우저에서만 동작하므로 서버 환경에선 절대 활성화되지 않아야 한다.

  • 개발 환경(dev)에서는 문제가 없었던 이유:

    개발 환경에서는 Webpack Dev Server와 Next.js의 유연한 오류 허용 정책 덕분에, Replay가 중복 초기화되더라도 전체 앱이 중단되지 않음.

    특히 dev 모드에서는 번들 최적화나 strict error 처리 없이, 대부분의 JS 예외를 브라우저가 로그만 출력하고 실행을 지속하기 때문.

    반면 production(Vercel) 환경에서는 JS 번들이 최적화되고, 오류 발생 시 실행이 즉시 중단되어 Replay 인스턴스 충돌이 앱 전체 렌더링 실패로 이어졌음.


4. 해결책

✒️ 단계별 조치 방법

Step 1: 중복된 설정 파일 sentry.config.ts 제거

  • 해당 파일이 클라이언트와 서버 모두에서 Sentry.init()을 실행하면서 Replay가 두 번 초기화됨.
  • instrumentation.ts, instrumentation-client.ts 두 파일만 유지하여 역할을 명확히 분리함.

Step 2: 클라이언트 전용 초기화 파일 작성 – instrumentation-client.ts


import * as Sentry from '@sentry/nextjs';

if (process.env.NODE_ENV === 'production') {
  Sentry.init({
    dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    tracesSampleRate: 1.0,
    replaysSessionSampleRate: 0.1,
    replaysOnErrorSampleRate: 1.0,
    integrations:
      typeof window !== 'undefined'
        ? [
            Sentry.replayIntegration({
              maskAllText: true,
              blockAllMedia: true,
            }),
          ]
        : [],
  });
}

export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

Step 3: 서버 전용 초기화 파일 작성 – instrumentation.ts

import * as Sentry from '@sentry/nextjs';

export function register() {
  if (process.env.NODE_ENV !== 'production') return;

  if (process.env.NEXT_RUNTIME === 'nodejs') {
    Sentry.init({
      dsn: process.env.SENTRY_DSN,
      tracesSampleRate: 1.0,
    });
  }

  if (process.env.NEXT_RUNTIME === 'edge') {
    Sentry.init({
      dsn: process.env.SENTRY_DSN,
    });
  }
}

export const onRequestError = Sentry.captureRequestError;

Step 4: App Router layout.tsx 또는 Root 컴포넌트에 Sentry.ErrorBoundary로 래핑

<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
  ...
   {children}
  ...
</Sentry.ErrorBoundary>

📚 참고 자료


5. 교훈 및 주의 사항

  • 주의할 점:
    • Sentry.init()딱 한 번만, 적절한 런타임 조건에서 실행되어야 함.
    • 클라이언트와 서버 환경의 경계가 모호할 경우, process.env.NEXT_RUNTIME, typeof window 등을 통해 환경 체크 필수
    • Replay는 브라우저에서만 실행, 서버에서 실행되면 window is not defined 오류 발생
  • 배운 점:
    • Replay는 매우 강력하지만 설정이 까다롭고, Next.js App Router에서는 명확한 분리가 필수
    • 모노레포에서는 여러 초기화 파일이 서로 중복 실행될 수 있으므로, 역할을 명확히 분리하고 중복을 방지해야 한다
    • JS가 아예 실행되지 않을 때는 Sentry와 같이 글로벌 단위에서 side effect를 줄 수 있는 라이브러리를 가장 먼저 의심하자
profile
Development Notes

0개의 댓글