본문으로 건너뛰기
개발 머꼬
개발 노트Nuxt.js
hohyeon.dev19

플러그인이 서버에서도 실행돼 window is not defined로 죽은 이유

  • #Engineering Note
  • #Nuxt.js

문제 발생

분석 도구를 붙이려고 플러그인을 만들었더니 서버 렌더에서 죽었습니다.

// app/plugins/analytics.ts
export default defineNuxtPlugin(() => {
  window.analytics.init(KEY);   // ReferenceError: window is not defined
});

한 파일을 하위 폴더로 옮겼더니 이번에는 아예 실행되지 않았고, 두 플러그인의 초기화 순서도 매번 달랐습니다.

원인 분석

플러그인은 기본적으로 양쪽에서 실행됩니다. Nuxt 문서는 app/plugins/ 디렉터리를 읽어 Vue 앱 생성 시점에 로드하며 안의 모든 플러그인이 자동 등록되어 nuxt.config에 따로 추가할 필요가 없다고 설명합니다. 여기에 실행 환경 구분은 없습니다.

자동 등록의 범위도 정해져 있습니다 — 디렉터리 최상위 파일(또는 하위 디렉터리의 index 파일)만 플러그인으로 자동 등록됩니다. 하위 폴더에 아무렇게나 넣으면 조용히 무시되는 이유입니다.

순서도 문서에 있습니다 — 기본적으로 플러그인은 순차적으로 로드되고, 파일명에 번호를 붙여 순서를 제어할 수 있습니다. 파일명은 문자열로 정렬되므로 01.처럼 자리를 맞춰야 하고(10.2.보다 앞섭니다), 특정 플러그인을 기다려야 하면 dependsOn을 씁니다.

해결 방안

  1. 환경은 파일명 접미사로 정합니다. 문서 설명 그대로 .server 또는 .client 접미사를 쓰면 그쪽에서만 로드됩니다.
app/plugins/analytics.client.ts    # 브라우저에서만
app/plugins/logger.server.ts       # 서버에서만
  1. 자동 등록되는 위치에 둡니다. 하위 폴더로 정리하고 싶으면 index 파일로 만들거나 nuxt.config.ts에 직접 등록합니다.

  2. 순서가 필요하면 명시합니다. 번호 접두사(01.setup.ts, 02.analytics.client.ts)나 dependsOn으로 의존을 드러냅니다 — 우연히 맞는 순서에 기대지 않습니다.

  3. 독립적인 플러그인은 병렬로 돌립니다. parallel: true를 주면 앞 플러그인의 완료를 기다리지 않아 부팅이 빨라집니다. 단 의존이 있는 것에는 쓰지 않습니다.

  4. 헬퍼 주입보다 컴포저블을 먼저 고려합니다. 문서가 직접 권합니다 — 전역 네임스페이스를 오염시키지 않도록 헬퍼 제공 대신 컴포저블 사용을 강력히 권장합니다. provide$hello를 만드는 대신 useHello()를 만드는 쪽입니다.

  5. window 접근은 접미사로 끝내지 말고 이유를 확인합니다. 접미사는 실행 위치를 정할 뿐, "이 기능이 SSR HTML에 있어야 하는가"는 별개 질문입니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.