106 lines
4.1 KiB
Vue
106 lines
4.1 KiB
Vue
<template>
|
|
<div style="font-family: sans-serif; max-width: 720px; margin: 60px auto; padding: 0 24px;">
|
|
<h1>Nuxt 4 렌더링 전략 데모</h1>
|
|
<p style="color: #666;">각 페이지에서 렌더링 방식의 차이를 확인해보세요.</p>
|
|
|
|
<div style="display: grid; gap: 16px; margin-top: 32px;">
|
|
<NuxtLink
|
|
v-for="page in pages"
|
|
:key="page.to"
|
|
:to="page.to"
|
|
style="display: block; padding: 20px 24px; border: 1px solid #e5e7eb; border-radius: 10px; text-decoration: none; color: inherit;"
|
|
>
|
|
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 6px;">
|
|
<span
|
|
style="font-size: 12px; font-weight: 600; padding: 2px 10px; border-radius: 99px; color: white;"
|
|
:style="{ background: page.color }"
|
|
>
|
|
{{ page.badge }}
|
|
</span>
|
|
<strong>{{ page.title }}</strong>
|
|
</div>
|
|
<p style="margin: 0; font-size: 14px; color: #6b7280;">{{ page.description }}</p>
|
|
</NuxtLink>
|
|
</div>
|
|
|
|
<!-- 전략 비교표 -->
|
|
<div style="margin-top: 48px;">
|
|
<h2 style="font-size: 16px; font-weight: 600; margin-bottom: 16px;">전략 비교</h2>
|
|
<div style="overflow-x: auto;">
|
|
<table style="width: 100%; border-collapse: collapse; font-size: 13px;">
|
|
<thead>
|
|
<tr style="background: #f9fafb;">
|
|
<th v-for="col in table.cols" :key="col" style="padding: 10px 14px; text-align: left; border: 1px solid #e5e7eb; font-weight: 600; white-space: nowrap;">
|
|
{{ col }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="row in table.rows" :key="row[0]">
|
|
<td
|
|
v-for="(cell, i) in row"
|
|
:key="i"
|
|
style="padding: 10px 14px; border: 1px solid #e5e7eb; white-space: nowrap;"
|
|
:style="getCellStyle(cell, i)"
|
|
v-html="cell"
|
|
/>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
function getCellStyle(cell: string, colIndex: number) {
|
|
if (colIndex === 0) return { fontWeight: '600' }
|
|
if (cell.includes('필요')) return { color: '#dc2626', fontWeight: '600' }
|
|
if (cell === '✓') return { color: '#10b981', fontWeight: '700', textAlign: 'center' as const }
|
|
if (cell === '✗') return { color: '#9ca3af', textAlign: 'center' as const }
|
|
return { color: '#374151' }
|
|
}
|
|
|
|
const table = {
|
|
cols: ['전략', '콘텐츠 최신성', '재배포', 'SEO', '서버 부하', '적합한 경우'],
|
|
rows: [
|
|
['SSR', '항상 최신', '불필요', '✓', '높음', '실시간 데이터, 개인화 페이지'],
|
|
['SSG', '빌드 시 고정', '변경 시 필요', '✓', '없음', '블로그, 문서, 변경이 드문 콘텐츠'],
|
|
['ISR', 'N초마다 갱신', '불필요', '✓', '낮음', '상품 목록, 뉴스 (준실시간)'],
|
|
['SWR', '매 요청 후 갱신', '불필요', '✓', '낮음', '대시보드 (약간의 지연 허용)'],
|
|
['SPA', '항상 최신', '불필요', '✗', '없음', '인증 후 관리자 페이지'],
|
|
],
|
|
}
|
|
|
|
const pages = [
|
|
{
|
|
to: '/ssr',
|
|
badge: 'SSR',
|
|
color: '#3b82f6',
|
|
title: 'Server-Side Rendering',
|
|
description: '요청마다 서버에서 HTML을 생성합니다. 페이지를 새로고침할 때마다 서버 시간이 바뀝니다.',
|
|
},
|
|
{
|
|
to: '/ssg',
|
|
badge: 'SSG',
|
|
color: '#10b981',
|
|
title: 'Static Site Generation',
|
|
description: '빌드 시점에 HTML을 미리 생성합니다. 새로고침해도 빌드 시간이 고정되어 있습니다.',
|
|
},
|
|
{
|
|
to: '/spa',
|
|
badge: 'SPA',
|
|
color: '#f59e0b',
|
|
title: 'Single Page Application',
|
|
description: '클라이언트에서만 렌더링합니다. 초기 HTML은 비어있고, JS 실행 후 데이터가 나타납니다.',
|
|
},
|
|
{
|
|
to: '/hybrid',
|
|
badge: 'Hybrid',
|
|
color: '#8b5cf6',
|
|
title: 'Hybrid / ISR',
|
|
description: 'nuxt.config의 routeRules로 경로마다 전략을 다르게 설정합니다. 이 페이지는 ISR(60초 캐시)입니다.',
|
|
},
|
|
]
|
|
</script>
|