Nuxt.js'te Rendering Stratejileri: SSR, CSR ve Hybrid Rendering
Nuxt.js, farklı rendering stratejileri sunarak modern web uygulamalarının ihtiyaçlarına uygun çözümler üretmemizi sağlar. Bu yazıda, Nuxt.js'in sunduğu rendering stratejilerini, kullanım senaryolarını ve performans optimizasyonlarını detaylı olarak inceleyeceğiz.
Rendering Stratejileri ve Kullanım Senaryoları
Server-Side Rendering (SSR)
SSR, sayfanın sunucu tarafında render edilip hazır HTML olarak gönderilmesi anlamına gelir. Bu yaklaşım özellikle SEO ve ilk yüklenme performansı için önemlidir.
// pages/blog/[slug].vue
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)
// SEO optimizasyonu için meta tags
useHead({
title: post.value?.title,
meta: [
{ name: 'description', content: post.value?.description },
{ property: 'og:title', content: post.value?.title },
{ property: 'og:description', content: post.value?.description }
]
})
</script>
<template>
<article v-if="post">
<h1>{{ post.title }}</h1>
<div v-html="post.content" />
</article>
</template>
Client-Side Rendering (CSR)
CSR, sayfanın tarayıcıda render edilmesi anlamına gelir. Bu yaklaşım, dinamik ve interaktif uygulamalar için uygundur.
// components/DynamicChart.client.vue
<script setup>
const { data: chartData } = await useFetch('/api/analytics')
const chartOptions = ref({
// Chart.js options
})
onMounted(() => {
// Client-side only code
initializeChart()
})
</script>
<template>
<div>
<canvas ref="chartRef" />
</div>
</template>
Hybrid Rendering
Hybrid rendering, SSR ve CSR'ın avantajlarını birleştiren modern bir yaklaşımdır.
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// SSR için statik sayfalar
'/': { static: true },
'/about': { static: true },
// ISR için blog sayfaları
'/blog/**': {
swr: 3600 // 1 saat cache
},
// CSR için dashboard
'/dashboard/**': {
ssr: false
}
}
})
Performans Optimizasyonu Teknikleri
1. Island Architecture
Island Architecture, sayfanın statik kısımlarını SSR ile, dinamik kısımlarını CSR ile render etme yaklaşımıdır.
<!-- components/IslandComponent.vue -->
<template>
<div class="island">
<!-- Statik içerik (SSR) -->
<header>
<h2>{{ title }}</h2>
<p>{{ description }}</p>
</header>
<!-- Dinamik içerik (CSR) -->
<ClientOnly>
<InteractiveWidget />
<template #fallback>
<LoadingSpinner />
</template>
</ClientOnly>
</div>
</template>
<script setup>
const props = defineProps<{
title: string
description: string
}>()
</script>
2. Incremental Static Regeneration (ISR)
ISR, statik sayfaların belirli aralıklarla yeniden oluşturulmasını sağlar.
// pages/products/[id].vue
<script setup>
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`, {
headers: useRequestHeaders(['cookie']),
key: route.params.id
})
// ISR için sayfa konfigürasyonu
definePageMeta({
static: true,
revalidate: 3600 // 1 saat
})
</script>
<template>
<div v-if="product">
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
<price-display :amount="product.price" />
</div>
</template>
3. Lazy Hydration
Lazy hydration, component'lerin hydration işlemini geciktirerek ilk yüklenme performansını iyileştirir.
<!-- components/HeavyComponent.vue -->
<script setup>
const isHydrated = ref(false)
onMounted(() => {
// Viewport'a girdiğinde hydrate et
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
isHydrated.value = true
observer.disconnect()
}
})
observer.observe(document.querySelector('#heavy-component'))
})
</script>
<template>
<div id="heavy-component">
<template v-if="isHydrated">
<!-- Hydrated content -->
<ComplexInteractiveComponent />
</template>
<template v-else>
<!-- Static placeholder -->
<StaticPlaceholder />
</template>
</div>
</template>
Veri Yönetimi ve Caching
1. Server State Management
// composables/useServerState.ts
export const useServerState = () => {
const state = useState('server-state', () => ({
cache: new Map(),
lastUpdated: null
}))
async function fetchWithCache(url: string, options = {}) {
const cacheKey = `${url}-${JSON.stringify(options)}`
if (state.value.cache.has(cacheKey)) {
return state.value.cache.get(cacheKey)
}
const data = await $fetch(url, options)
state.value.cache.set(cacheKey, data)
state.value.lastUpdated = new Date()
return data
}
return {
state: readonly(state),
fetchWithCache
}
}
2. Hybrid Data Fetching
// composables/useHybridData.ts
export const useHybridData = <T>(
url: string,
options: UseFetchOptions = {}
) => {
const config = useRuntimeConfig()
const isServer = process.server
// SSR için veri fetch
const { data: ssrData } = useFetch<T>(url, {
...options,
server: true,
key: `ssr-${url}`
})
// CSR için veri güncelleme
const { data: liveData, refresh } = useFetch<T>(url, {
...options,
server: false,
key: `csr-${url}`,
immediate: !isServer
})
// Combine SSR and CSR data
const data = computed(() => liveData.value || ssrData.value)
return {
data,
refresh
}
}
SEO ve Performance Monitoring
1. Dynamic Meta Tags
// plugins/seo.ts
export default defineNuxtPlugin(() => {
const generateMeta = (page: PageMeta) => {
useHead({
title: page.title,
meta: [
{
name: 'description',
content: page.description
},
{
property: 'og:title',
content: page.title
},
{
property: 'og:description',
content: page.description
},
{
name: 'twitter:card',
content: 'summary_large_image'
}
],
link: [
{
rel: 'canonical',
href: `${useRuntimeConfig().public.siteUrl}${useRoute().path}`
}
]
})
}
return {
provide: {
seo: {
generateMeta
}
}
}
})
2. Performance Monitoring
// plugins/performance.ts
export default defineNuxtPlugin(() => {
const performanceMetrics = {
fcp: null, // First Contentful Paint
lcp: null, // Largest Contentful Paint
fid: null, // First Input Delay
cls: null // Cumulative Layout Shift
}
if (process.client) {
// FCP
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries()
performanceMetrics.fcp = entries[entries.length - 1]
}).observe({ type: 'paint', buffered: true })
// LCP
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries()
performanceMetrics.lcp = entries[entries.length - 1]
}).observe({ type: 'largest-contentful-paint', buffered: true })
// FID
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries()
performanceMetrics.fid = entries[entries.length - 1]
}).observe({ type: 'first-input', buffered: true })
// CLS
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries()
performanceMetrics.cls = entries[entries.length - 1]
}).observe({ type: 'layout-shift', buffered: true })
}
return {
provide: {
performance: performanceMetrics
}
}
})
Best Practices ve Öneriler
Rendering Stratejisi Seçimi:
- SEO önemliyse SSR
- Yüksek interaktivite gerekiyorsa CSR
- Her ikisi de gerekiyorsa Hybrid Rendering
Performance Optimizasyonu:
- Lazy loading
- Code splitting
- Cache stratejileri
- Image optimization
SEO:
- Meta tags
- Structured data
- Canonical URLs
- Sitemap
Monitoring:
- Core Web Vitals
- Error tracking
- User analytics
- Performance metrics
Sonuç
Nuxt.js'in sunduğu rendering stratejileri, modern web uygulamalarının farklı ihtiyaçlarına cevap verebilecek esneklikte çözümler sunar. Projenizin gereksinimlerine göre doğru rendering stratejisini seçmek ve optimizasyon tekniklerini uygulamak, başarılı bir web uygulaması geliştirmenin anahtarıdır.
İlgili Etiketler: #Nuxtjs #SSR #CSR #HybridRendering #Performance #SEO #WebDevelopment