Dilema Arsitektur: Dynamic SSR vs Hybrid Rendering
Server-Side Rendering (SSR) dinamis murni mengeksekusi siklus hidup Vue dan permintaan data backend pada setiap inbound request. Pola ini menjamin data selalu segar, namun menimbulkan biaya komputasi V8 yang linier terhadap volume trafik. Ketika trafik melonjak, bottleneck berpindah ke thread JavaScript runtime dan antrean koneksi database.
Nuxt 3 mengatasi batas skalabilitas ini melalui Hybrid Rendering yang didukung oleh engine Nitro. Melalui konfigurasi routeRules, developer dapat menentukan strategi rendering per rute secara granular: On-Demand Dynamic SSR, Server-side Revalidation (SWR), atau Incremental Static Regeneration (ISR). Namun, beralih ke ISR bukan solusi instan tanpa konsekuensi teknis. Pendekatan ini memperkenalkan latensi revalidasi, kompleksitas invalidasi storage, dan risiko kebocoran data pengguna.
Mekanisme Eksekusi: Siklus Hidup Request
1. Dynamic SSR (On-Demand)
Pada dynamic SSR murni, alur eksekusi terjadi secara serial:
- Klien mengirimkan request HTTP.
- Nitro menginisialisasi context, mengeksekusi middleware, dan memanggil
useAsyncDataatau API backend terkait. - Runtime me-render virtual DOM menjadi HTML string melalui
vue/server-renderer. - Payload HTML dan serialisasi state (
piniaatauuseState) dikirimkan ke klien.
Kelemahan utama: Lonjakan beban menghasilkan peningkatan Time to First Byte (TTFB) secara eksponensial saat CPU terbebani tugas rendering DOM dan eksekusi event-loop terblokir oleh serialisasi data besar.
2. ISR dan SWR (Nitro Engine Cache)
SWR dan ISR menyimpan hasil render HTML ke dalam layer unstorage bawaan Nitro. Perbedaannya terletak pada perilaku CDN dan storage adapter:
- SWR (Stale-While-Revalidate): Nitro langsung menyajikan respons dari cache (stale) jika tersedia, lalu menjalankan background task untuk me-render ulang halaman dan memperbarui cache secara asinkron.
- ISR (Incremental Static Regeneration): Menyelaraskan cache lokal Nitro dengan CDN edge cache menggunakan header
Cache-Controltertentu, mempertahankan halaman statis hingga periode TTL (Time-to-Live) kedaluwarsa sebelum revalidasi diinisiasi.
Analisis Trade-off Teknis
1. TTFB dan Beban Query Database
Pada Dynamic SSR, database relasional atau microservice hulu menerima thundering herd problem saat ribuan klien mengakses rute yang sama secara simultan. Pada ISR/SWR, query hulu dipadatkan menjadi satu pemanggilan periodik sesuai interval revalidasi. TTFB terpangkas dari ratusan milidetik (atau hitungan detik saat komputasi tinggi) menjadi single-digit milidetik karena respons disajikan langsung dari memory/storage.
2. Eventual Consistency dan Cache Invalidation
Kelemahan fundamental ISR adalah integritas konsistensi data (eventual consistency). Jika stok produk berubah di database, halaman ISR tetap menampilkan data lama hingga siklus revalidasi selesai atau cache dibersihkan secara eksplisit.
Invalidasi programmatic di Nuxt 3 memerlukan interaksi langsung dengan layer storage Nitro. Nitro menyimpan cache rute terkomputasi di namespace cache:nitro:routes.
// server/api/purge-cache.post.ts
import { defineEventHandler, readBody, createError } from 'h3'
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const token = getHeader(event, 'x-invalidation-secret')
if (token !== process.env.PURGE_SECRET_TOKEN) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
}
// Akses storage engine Nitro
const storage = useStorage('cache:nitro:routes')
// Format key internal Nitro: _[route_path].json / .html
const cacheKey = `_${body.path}.json`
if (await storage.hasItem(cacheKey)) {
await storage.removeItem(cacheKey)
return { purged: true, path: body.path }
}
return { purged: false, message: 'Cache key not found' }
})Perhatian: Invalidasi manual berbasis event memicu peningkatan kompleksitas operasional pada sistem terdistribusi bila Nitro instance berjalan pada banyak container terpisah tanpa storage bersama (shared storage).
3. Maintainability: Pemisahan Rute Publik dan State Terotentikasi
Pola anti-pattern paling berbahaya pada Nuxt 3 adalah mengaktifkan ISR/SWR pada rute yang membaca identitas pengguna (seperti auth cookie atau token JWT di header).
Jika halaman yang di-render membaca state otentikasi di level server, HTML yang mengandung data spesifik akun pengguna pertama akan tersimpan di Nitro storage dan dibagikan secara terbuka kepada pengunjung berikutnya (cache poisoning/credential leaking).
Aturan arsitektur:
- Gunakan ISR/SWR secara eksklusif untuk rute publik/anonim (e.g., katalog produk, dokumentasi, landing page).
- Untuk rute terotentikasi, gunakan dynamic SSR atau alihkan ke Client-Side Rendering (CSR) dengan
ssr: falsepadarouteRules. - Jika rute publik membutuhkan komponen terotentikasi (seperti badge keranjang belanja di navbar), render navbar sebagai
<ClientOnly>atau load data melalui API terpisah dari sisi klien.
Analisis Biaya Operasional: Komputasi vs Penyimpanan
| Komponen | Dynamic SSR Murni | Hybrid Rendering (ISR/SWR) |
|---|---|---|
| Beban CPU Server | Tinggi (re-render DOM dan parsing data per request). | Rendah (hanya terbebani saat interval revalidasi). |
| Kebutuhan RAM | Tinggi (footprint memori V8 bertambah seiring konkurensi). | Dapat diprediksi, proporsional terhadap ukuran footprint cache HTML. |
| Infrastruktur Cache | Tidak memerlukan distributed storage runtime. | Membutuhkan backend unstorage (Redis/Valkey) atau filesystem SSD. |
| Beban Database | Linier terhadap request masuk (N request = N queries). | Dibatasi oleh interval TTL (N request = 1 query per periode). |
Contoh Konfigurasi nuxt.config.ts Skala Produksi
Konfigurasi di bawah mendemonstrasikan pemetaan strategi rendering berbasis rute dan konfigurasi Redis sebagai backend storage Nitro terpusat untuk traffic tinggi multi-instance.
// nuxt.config.ts
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
nitro: {
// Shared storage untuk cache horizontal scaling
storage: {
'cache:nitro:routes': {
driver: 'redis',
host: process.env.REDIS_HOST || '127.0.0.1',
port: Number(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
db: 0,
ttl: 60 * 60 * 24 // Default fallback 24 jam
}
}
},
routeRules: {
// 1. Landing page & konten statis: Static Generation
'/': { prerender: true },
'/about': { prerender: true },
// 2. Katalog publik dengan perubahan periodik: ISR 10 Menit
'/products': { isr: 600 },
'/products/**': { isr: 600 },
// 3. Blog/Artikel: SWR dengan stale response instan
'/blog/**': { swr: 3600 },
// 4. Halaman dinamis sensitif data real-time: Dynamic SSR
'/search': { ssr: true },
// 5. Area terotentikasi: Client-Side Rendering murni (hemat compute server)
'/admin/**': { ssr: false },
'/checkout/**': { ssr: false }
}
})Matriks Keputusan Arsitektur
Pilih strategi rendering Nuxt 3 berdasarkan karakteristik data dan toleransi latensi rute Anda:
- Prerender (Static): Data hampir tidak pernah berubah (Docs, Privacy Policy, Terms). Dibangun saat
npm run build. - ISR (Incremental Static Regeneration): Halaman publik bervolume tinggi, data jarang diperbarui dalam rentang menit (Detail Produk e-commerce, direktori listing). Prioritas: TTFB terendah dan SEO optimal.
- SWR (Stale-While-Revalidate): Halaman dengan update berkala yang toleran terhadap stale data sesaat (Portal berita, feed blog). Menjamin TTFB instan bagi user kedua dan seterusnya.
- Dynamic SSR: Halaman publik yang membutuhkan data 100% konsisten detik itu juga (Hasil pencarian dengan filter kompleks, tracking order publik).
- SPA (Client-Side Rendering via
ssr: false): Area dashboard tertutup, rute transaksi, atau form data sensitif. Menghilangkan beban server render sekaligus menghindari risiko kebocoran session storage.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!