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

document.cookie로 읽던 값이 SSR에서 undefined였던 이유

  • #Engineering Note
  • #Nuxt.js

문제 발생

테마 설정을 쿠키에 저장하고 SSR에서도 반영하려 했습니다.

const theme = document.cookie.match(/theme=(\w+)/)?.[1];   // 서버에서 터짐
ReferenceError: document is not defined

if (import.meta.client)로 감싸자 오류는 사라졌지만, 이번에는 서버 렌더에 테마가 반영되지 않아 화면이 한 번 깜빡였습니다.

원인 분석

document는 서버에 없습니다. SSR에서 쿠키는 브라우저 저장소가 아니라 들어온 요청의 헤더에 있고, 응답에 쿠키를 실으려면 Set-Cookie 헤더를 써야 합니다. 두 환경의 접근 방식이 다르기 때문에, 조건 분기로 한쪽을 꺼버리면 SSR 결과에서 그 값이 통째로 빠집니다.

Nuxt는 이 차이를 감춘 컴포저블을 제공합니다. 문서는 useCookie쿠키를 읽고 쓰는 SSR 친화적 컴포저블로 소개하며, 반환된 ref가 값의 JSON 직렬화/역직렬화까지 처리한다고 설명합니다. 그리고 ref를 갱신하면 쿠키가 갱신됩니다(readonly가 아닌 경우).

주의사항도 함께 있습니다 — useCookie는 Nuxt 컨텍스트에서만 동작하고, 쿠키가 외부에서 바뀐 경우에는 refreshCookie로 값을 수동으로 갱신해야 합니다.

해결 방안

  1. 읽기와 쓰기를 하나의 ref로 다룹니다.
const theme = useCookie<"light" | "dark">("theme", {
  maxAge: 60 * 60 * 24 * 365,
  sameSite: "lax",
  path: "/",
});

theme.value = "dark";   // 쿠키까지 갱신된다
  1. 인증 토큰은 화면 상태와 구분합니다. 세션 토큰은 서버에서 httpOnly로 심고, 클라이언트가 읽는 쿠키는 테마·언어처럼 노출돼도 되는 값만 담습니다.

  2. 옵션을 상황에 맞게 고릅니다. 문서가 나열하는 maxAge, expires, httpOnly, secure, sameSite, readonly, watch 중 필요한 것만 씁니다. 다만 httpOnly 쿠키는 클라이언트에서 읽을 수 없으므로 화면 상태용으로는 맞지 않습니다.

  3. 서버 라우트에서 쿠키를 바꿨다면 새로 읽습니다. API 호출로 값이 바뀐 뒤에는 refreshCookie("theme")을 호출해야 화면의 ref가 최신이 됩니다.

  4. 깜빡임(FOUC)을 실제로 확인합니다. 서버 렌더 HTML에 그 값이 이미 들어 있는지 보는 게 유일한 검증입니다 — JS를 끄고 페이지를 열어보면 바로 드러납니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

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