Files
nuxt-deep/app/pages/index.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>