Files
gil-wiki/wiki/nuxt-performance.md
gil 5f664546cf feat: 위키 저장소 초기 커밋
- CLAUDE.md 운영 규칙
- wiki/ 정리된 지식 페이지 (Nuxt + Claude Code)
- raw/ 원본 자료
- reference/ Nuxt 4.x 공식 문서

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 00:31:51 +09:00

6.3 KiB

Nuxt 성능 최적화 & 하이드레이션

카테고리: 성능 & 배포 최종 수정: 2026-05-13 관련: nuxt-rendering-modes, nuxt-lifecycle, nuxt-data-fetching

요약

Nuxt 성능 최적화는 내장 기능(Lazy 컴포넌트, 스마트 프리패치, 데이터 캐싱)과 공식 모듈(Image, Fonts, Scripts), 그리고 하이드레이션 오류 방지 세 가지 축으로 나뉜다.


내장 성능 기능

<NuxtLink>가 뷰포트에 들어오면 자동으로 다음 페이지의 JS와 payload 프리패치.

<NuxtLink to="/about">소개</NuxtLink>

뷰포트 대신 인터랙션 시 프리패치로 변경:

export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        prefetchOn: { interaction: true, visibility: false },
      },
    },
  },
})

Lazy 컴포넌트 (지연 로딩)

Lazy 접두사로 컴포넌트 지연 로딩. 번들 크기 최소화.

<template>
  <div>
    <LazyMountainsList v-if="show" />
    <button v-else @click="show = true">목록 보기</button>
  </div>
</template>

Lazy Hydration (Nuxt v3.16+)

초기 로드 시 모든 컴포넌트를 인터랙티브하게 만들지 않아도 됨.

<template>
  <LazyMyComponent hydrate-on-visible />       <!-- 뷰포트 진입  -->
  <LazyHeavyChart hydrate-on-idle />           <!-- 브라우저 유휴  -->
  <LazyModal hydrate-on-interaction="click" /> <!-- 인터랙션  -->
</template>

데이터 이중 패칭 방지

useFetch / useAsyncData는 서버에서 가져온 데이터를 payload로 전달 → 클라이언트에서 재요청 없이 재사용.


Hybrid Rendering으로 성능 극대화

export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },       // 빌드 시 생성
    '/products/**': { swr: 3600 }, // 1시간 캐시 + 백그라운드 재생성
    '/blog': { isr: 3600 },        // CDN 캐시 1시간
    '/admin/**': { ssr: false },    // 클라이언트 전용
  },
})

공식 모듈

Nuxt Image

이미지 자동 최적화, WebP/Avif 변환, lazy loading.

<template>
  <!-- LCP 이미지: eager + high priority -->
  <NuxtImg
    src="/hero-banner.jpg"
    format="webp"
    :preload="{ fetchPriority: 'high' }"
    loading="eager"
    width="200"
    height="100"
  />

  <!-- 일반 이미지: lazy loading -->
  <NuxtImg
    src="/thumbnail.jpg"
    format="webp"
    loading="lazy"
    fetchpriority="low"
    width="100"
    height="100"
  />
</template>

Nuxt Fonts

폰트 자동 self-hosting, CLS 감소, 캐시 헤더 설정. CSS font-family 선언만 있으면 나머지 자동 처리.

Nuxt Scripts

서드파티 스크립트(GA, 지도, SNS) 성능 최적화.

const { proxy } = useScriptGoogleAnalytics({
  id: 'G-1234567',
  scriptOptions: { trigger: 'manual' },
})
proxy.gtag('config', 'UA-123456789-1')

하이드레이션 오류

하이드레이션 오류 = 서버에서 렌더링한 HTML과 클라이언트에서 Vue가 생성하는 DOM이 불일치. 단순 경고가 아님 — 인터랙티비티 지연, 이벤트 리스너 미연결, 상태 불일치 야기.

주요 원인과 해결법

1. 브라우저 전용 API를 서버에서 사용

<!--  localStorage는 서버에서 없음 -->
<script setup>
const theme = localStorage.getItem('theme') || 'light'
</script>

<!--  useCookie 사용 -->
<script setup>
const theme = useCookie('theme', { default: () => 'light' })
</script>

2. 서버·클라이언트 데이터 불일치

<!--  서버와 클라이언트에서 다른  -->
<template><div>{{ Math.random() }}</div></template>

<!--  useState로 일관된  유지 -->
<script setup>
const state = useState('random', () => Math.random())
</script>
<template><div>{{ state }}</div></template>

3. 시간 기반 조건 렌더링

<!--  서버와 클라이언트의 시각이 다름 -->
<script setup>
const hour = new Date().getHours()
const greeting = hour < 12 ? 'Good morning' : 'Good afternoon'
</script>

<!--  NuxtTime 컴포넌트 또는 onMounted에서 처리 -->
<script setup>
const greeting = ref('Hello!')
onMounted(() => {
  const hour = new Date().getHours()
  greeting.value = hour < 12 ? '좋은 아침입니다' : '안녕하세요'
})
</script>

4. 서드파티 라이브러리 DOM 조작

<!--  서버에서 import  에러 -->
<script setup>
if (import.meta.client) {
  const { default: SomeLib } = await import('browser-only-lib')
  SomeLib.init()
}
</script>

<!--  onMounted에서 초기화 -->
<script setup>
onMounted(async () => {
  const { default: SomeLib } = await import('browser-only-lib')
  SomeLib.init()
})
</script>

5. ClientOnly로 클라이언트 전용 콘텐츠 격리

<template>
  <ClientOnly>
    <BrowserOnlyComponent />
    <template #fallback>
      <p>로딩 ...</p>
    </template>
  </ClientOnly>
</template>

하이드레이션 오류 체크리스트

  • localStorage, window, documentonMounted 또는 import.meta.client로 분기
  • Math.random(), Date.now()useState로 서버 값 유지
  • window.innerWidth 조건 렌더링 → CSS 미디어 쿼리로 대체
  • 서드파티 라이브러리 초기화 → onMounted 안으로 이동
  • SSR 중 사이드 이펙트 → <script setup> 루트가 아닌 onMounted 내부로

성능 측정 도구

도구 용도
nuxi analyze 번들 시각화 (vite-bundle-visualizer)
Nuxt DevTools Timeline, Render Tree, Inspect
Chrome DevTools > Performance LCP, CLS, INP
Chrome Lighthouse 종합 성능·접근성·SEO 감사
PageSpeed Insights 실사용자 필드 데이터 포함

흔한 성능 실수

문제 해결
플러그인 과다 사용 composable 또는 유틸 함수로 대체
미사용 의존성 package.json 정기 점검, 번들 분석
Vue 최적화 미적용 shallowRef, v-memo, v-once 활용
모든 것을 동시 로딩 Progressive Enhancement, Lazy 컴포넌트

참고 / 출처

  • reference/3.guide/2.best-practices/performance.md
  • reference/3.guide/2.best-practices/hydration.md