104 lines
4.0 KiB
Vue
104 lines
4.0 KiB
Vue
<template>
|
|
<PageLayout badge="Hybrid" badge-color="#8b5cf6" title="Hybrid / ISR">
|
|
<InfoRow label="렌더링 방식" value="ISR (Incremental Static Regeneration)" />
|
|
<InfoRow label="캐시 TTL" value="60초" />
|
|
<InfoRow label="서버 렌더링 시간 (캐시됨)" :value="data?.time ?? '로딩 중...'" highlight />
|
|
<InfoRow label="클라이언트 현재 시간 (실시간)" :value="clientTime" highlight />
|
|
<InfoRow label="캐시 경과" :value="elapsedText" />
|
|
|
|
<!-- 환경 안내 배너 -->
|
|
<div
|
|
:style="{
|
|
marginTop: '12px',
|
|
padding: '10px 14px',
|
|
borderRadius: '8px',
|
|
fontSize: '13px',
|
|
background: isDev ? '#fef3c7' : '#d1fae5',
|
|
color: isDev ? '#92400e' : '#065f46',
|
|
border: isDev ? '1px solid #fcd34d' : '1px solid #6ee7b7',
|
|
}"
|
|
>
|
|
<strong>{{ isDev ? '⚠ 개발 모드' : '✓ 프로덕션 모드' }}</strong>
|
|
{{ isDev
|
|
? ' — ISR은 개발 서버에서 동작하지 않습니다. nuxt build 후 nuxt preview로 확인하세요.'
|
|
: ' — ISR이 활성화되어 있습니다. 서버 렌더링 시간이 60초간 고정됩니다.'
|
|
}}
|
|
</div>
|
|
|
|
<template #explain>
|
|
<li>
|
|
<strong>ISR 동작 흐름:</strong> 첫 요청 시 서버 렌더링 및 캐시 저장
|
|
→ 60초 이내 재방문 시 캐시된 HTML 즉시 반환
|
|
→ 60초 경과 후 첫 요청에서 캐시 반환 + 백그라운드 재생성
|
|
→ 다음 요청부터 새 HTML 반환
|
|
</li>
|
|
<li>
|
|
<strong>확인 방법:</strong>
|
|
<ol style="margin: 4px 0 0; padding-left: 20px;">
|
|
<li><code>npm run build</code> → <code>npm run preview</code> 실행</li>
|
|
<li>이 페이지를 열고 <strong>서버 렌더링 시간</strong> 기록</li>
|
|
<li>60초 이내 새로고침 → 서버 시간이 <strong>동일</strong>함 (캐시)</li>
|
|
<li>60초 후 새로고침 → 여전히 이전 값 (캐시 반환 + 백그라운드 재생성 시작)</li>
|
|
<li>한 번 더 새로고침 → 서버 시간이 <strong>변경</strong>됨 (새 HTML)</li>
|
|
</ol>
|
|
</li>
|
|
<li><code>swr: true</code>는 TTL 없이 항상 캐시를 반환하고 매 요청마다 백그라운드 갱신합니다.</li>
|
|
<li>한 앱에서 SSR / SSG / SPA / ISR을 경로마다 다르게 혼합할 수 있습니다.</li>
|
|
</template>
|
|
|
|
<template #code>
|
|
<pre>{{ codeExample }}</pre>
|
|
</template>
|
|
</PageLayout>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const { data } = await useFetch('/api/time')
|
|
|
|
// 클라이언트 실시간 시계
|
|
const clientTime = ref('')
|
|
const elapsedText = ref('-')
|
|
|
|
let interval: ReturnType<typeof setInterval>
|
|
|
|
onMounted(() => {
|
|
const serverTime = data.value?.time ? new Date(data.value.time) : null
|
|
|
|
interval = setInterval(() => {
|
|
const now = new Date()
|
|
clientTime.value = now.toISOString()
|
|
|
|
if (serverTime) {
|
|
const elapsed = Math.floor((now.getTime() - serverTime.getTime()) / 1000)
|
|
const remaining = Math.max(0, 60 - elapsed)
|
|
elapsedText.value = elapsed < 60
|
|
? `${elapsed}초 경과 — 캐시 유효 (${remaining}초 남음)`
|
|
: `${elapsed}초 경과 — 캐시 만료, 다음 요청 시 재생성`
|
|
}
|
|
}, 1000)
|
|
})
|
|
|
|
onUnmounted(() => clearInterval(interval))
|
|
|
|
// 개발/프로덕션 구분
|
|
const isDev = import.meta.dev
|
|
|
|
const codeExample = `// nuxt.config.ts — 경로별 전략 혼합
|
|
export default defineNuxtConfig({
|
|
routeRules: {
|
|
'/': { prerender: true }, // SSG
|
|
'/blog/**': { isr: 3600 }, // ISR (1시간 캐시)
|
|
'/products/**': { swr: true }, // Stale-While-Revalidate
|
|
'/dashboard/**':{ ssr: false }, // SPA
|
|
'/hybrid': { isr: 60 }, // ISR (60초 캐시) ← 이 페이지
|
|
},
|
|
})
|
|
|
|
// ISR 확인 방법
|
|
// 1. npm run build
|
|
// 2. npm run preview
|
|
// 3. /hybrid 접속 후 서버 렌더링 시간 기록
|
|
// 4. 60초 이내 새로고침 → 동일한 시간 (캐시)
|
|
// 5. 60초 후 새로고침 2회 → 시간 변경 (재생성 완료)`
|
|
</script>
|