브라우저 전용 라이브러리를 넣었더니 서버에서 window is not defined로 죽은 이유
문제 발생
지도 라이브러리를 페이지에 넣자 빌드가 죽었습니다.
ReferenceError: window is not definedssr: false를 주면 된다고 해서 페이지(Server Component)에 그대로 썼더니 이번에는 다른 오류가 났습니다.
`ssr: false` is not allowed with `next/dynamic` in Server Components.원인 분석
두 가지가 얽혀 있습니다.
첫째, Client Component도 서버에서 한 번 렌더됩니다. Next.js 문서가 명확히 합니다 — React.lazy()와 Suspense를 쓰면 Client Component가 기본적으로 프리렌더(SSR)됩니다. 그래서 window를 모듈 최상단에서 만지는 라이브러리는 그 시점에 죽습니다.
둘째, ssr: false는 Client Component 전용입니다. 문서의 경고 그대로 — ssr: false 옵션은 Server Component에서 지원되지 않으며, 시도하면 오류가 납니다. Client Component로 옮기십시오.
문서는 지연 로딩의 적용 범위도 정리합니다 — Server Component는 자동으로 코드 분할되며, 지연 로딩은 Client Component에 적용됩니다.
해결 방안
- 클라이언트 경계를 하나 만들고 그 안에서 동적 로딩합니다.
// components/map-view.tsx
"use client";
import dynamic from "next/dynamic";
const Map = dynamic(() => import("./map"), {
ssr: false,
loading: () => <MapSkeleton />,
});
export function MapView(props: MapProps) {
return <Map {...props} />;
}페이지(Server Component)는 <MapView />만 렌더합니다.
-
loading옵션으로 자리를 잡아둡니다. 지도처럼 큰 영역은 스켈레톤이 없으면 레이아웃이 크게 흔들립니다. -
조건부로 열리는 것에 우선 적용합니다. 문서가 드는 예처럼 사용자가 클릭해서 열기 전까지 모달 로딩을 미루는 경우가 대표적입니다.
-
외부 라이브러리는 함수 안에서
import()합니다. 문서 예제처럼 입력이 시작될 때 검색 라이브러리를 불러오면, 그 전까지는 번들에 포함되지 않습니다. -
SSR을 끄는 대가를 인지합니다. 그 영역은 초기 HTML에 없습니다 — 검색 유입이 필요한 콘텐츠에는 쓰지 않습니다.
-
ssr: false없이 되는지 먼저 봅니다. 브라우저 API 접근을useEffect안으로 옮기는 것만으로 해결되는 경우가 많고, 그러면 서버 렌더 결과를 유지할 수 있습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.