# Nuxt 3: SSR dan generasi statis, panduan lengkap > Menguasai SSR dan generasi statis dengan Nuxt 3. Dari useFetch hingga route rules, pelajari cara mengoptimalkan performa aplikasi Vue.js. - Published: 2026-02-11 - Updated: 2026-04-28 - Author: SharpSkill - Tags: nuxt 3, vue.js, ssr, generasi statis, performa web - Reading time: 12 min --- Nuxt 3 mengubah cara aplikasi Vue.js dibangun dengan menyediakan beberapa mode rendering yang sesuai untuk berbagai kasus penggunaan. Dari Server-Side Rendering (SSR) hingga generasi statis dan rendering hibrida, framework ini memberikan fleksibilitas luar biasa untuk mengoptimalkan performa dan SEO. > **Prasyarat** > > Tutorial ini mengasumsikan pengetahuan dasar tentang Vue 3 dan Composition API. Keakraban dengan konsep rendering sisi server akan membantu, tetapi tidak wajib, karena dasar-dasarnya dijelaskan di sepanjang panduan. ## Memahami mode rendering Nuxt 3 Sebelum menyelami kode, penting untuk memahami perbedaan antara mode rendering yang tersedia. Setiap mode menjawab kebutuhan spesifik dalam hal performa, SEO, dan pengalaman pengguna. SSR (Server-Side Rendering) menghasilkan HTML di server untuk setiap permintaan. Generasi statis (SSG) membuat semua halaman terlebih dahulu pada saat build. Mode hibrida memungkinkan kombinasi pendekatan ini per halaman. ```typescript // nuxt.config.ts // Konfigurasi berbagai mode rendering export default defineNuxtConfig({ // SSR aktif secara default (direkomendasikan untuk SEO) ssr: true, // Generasi statis: pra-render semua halaman // Gunakan 'npm run generate' untuk build // target: 'static', // Sintaks Nuxt 2 // Mode hibrida: dapat dikonfigurasi per route routeRules: { // Halaman beranda: di-pra-render dan disimpan dalam cache '/': { prerender: true }, // Blog: generasi statis '/blog/**': { prerender: true }, // Dashboard: rendering hanya di sisi klien '/dashboard/**': { ssr: false }, // API: tanpa pra-rendering '/api/**': { prerender: false } } }) ``` Konfigurasi ini menunjukkan kekuatan mode hibrida: setiap bagian aplikasi menggunakan mode rendering yang paling sesuai dengan kebutuhannya. ## Pengambilan data dengan useFetch dan useAsyncData Nuxt 3 menyediakan dua composable utama untuk mengambil data secara isomorfik. Composable ini bekerja baik di sisi server maupun klien, dengan manajemen hidrasi otomatis. `useFetch` adalah wrapper di sekitar `useAsyncData` yang menyederhanakan panggilan HTTP. `useAsyncData` memberikan kontrol lebih untuk kasus penggunaan tingkat lanjut. ```vue ``` Untuk kasus yang membutuhkan kontrol lebih, `useAsyncData` memungkinkan eksekusi fungsi asinkron apa pun. ```vue ``` Composable ini mencegah double fetching: data yang diperoleh di server diserialisasi ke dalam payload HTML dan digunakan kembali selama hidrasi di sisi klien. ## Menyesuaikan SSR dengan server hooks SSR di Nuxt 3 dapat disesuaikan melalui server hooks. Hook ini memungkinkan intervensi pada berbagai tahap siklus rendering untuk memodifikasi perilaku default. ```typescript // server/plugins/render-hooks.ts // Plugin server untuk menyesuaikan rendering SSR export default defineNitroPlugin((nitroApp) => { // Hook yang dijalankan sebelum rendering setiap halaman nitroApp.hooks.hook('render:html', (html, { event }) => { // Menyuntikkan script atau metadata html.head.push(` `) }) // Hook untuk pengelolaan cache rendering nitroApp.hooks.hook('render:response', (response, { event }) => { // Menambahkan header cache kustom const path = event.path if (path.startsWith('/blog/')) { // Cache panjang untuk artikel blog response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400' } else if (path.startsWith('/api/')) { // Tanpa cache untuk API response.headers['Cache-Control'] = 'no-store' } }) }) ``` > **Performa SSR** > > Hook `render:response` ideal untuk menerapkan strategi cache HTTP. Menggabungkan SSR dengan CDN yang menghormati header Cache-Control memungkinkan penyajian halaman pra-render sambil tetap dapat melakukan invalidasi. ## Generasi statis dengan nuxt generate Generasi statis membangun semua halaman terlebih dahulu pada saat build. Pendekatan ini ideal untuk situs dengan konten stabil seperti blog, dokumentasi, atau situs marketing. Untuk route dinamis, Nuxt perlu mengetahui semua URL yang akan dihasilkan. Hook `prerender:routes` memungkinkan pendefinisian route ini secara programatik. ```typescript // nuxt.config.ts // Konfigurasi lengkap untuk generasi statis export default defineNuxtConfig({ // Mengaktifkan generasi statis nitro: { prerender: { // Mengaktifkan crawling link otomatis crawlLinks: true, // Route yang harus selalu disertakan routes: ['/', '/about', '/contact'], // Mengabaikan route tertentu ignore: ['/admin', '/api'] } }, hooks: { // Hook untuk menghasilkan route dinamis async 'prerender:routes'(ctx) { // Mengambil artikel dari API atau DB const articles = await fetch('https://api.example.com/articles') .then(res => res.json()) // Menambahkan route artikel for (const article of articles) { ctx.routes.add(`/blog/${article.slug}`) } // Mengambil kategori const categories = await fetch('https://api.example.com/categories') .then(res => res.json()) for (const category of categories) { ctx.routes.add(`/category/${category.slug}`) } } } }) ``` Untuk proyek dengan banyak halaman, crawler otomatis mungkin tidak cukup. Berikut pendekatan yang lebih kuat dengan file konfigurasi terpisah. ```typescript // server/utils/generate-routes.ts // Utilitas untuk menghasilkan daftar route dinamis import { prisma } from './prisma' export async function getAllStaticRoutes(): Promise { const routes: string[] = [] // Artikel blog const articles = await prisma.article.findMany({ where: { published: true }, select: { slug: true, category: { select: { slug: true } } } }) for (const article of articles) { routes.push(`/blog/${article.category.slug}/${article.slug}`) } // Halaman produk const products = await prisma.product.findMany({ where: { active: true }, select: { slug: true } }) for (const product of products) { routes.push(`/products/${product.slug}`) } // Halaman tag const tags = await prisma.tag.findMany({ select: { slug: true } }) for (const tag of tags) { routes.push(`/tags/${tag.slug}`) } return routes } ``` ## Rendering hibrida dengan routeRules Rendering hibrida adalah fitur unggulan Nuxt 3. Fitur ini memungkinkan pendefinisian aturan rendering yang berbeda per route, menggabungkan keunggulan SSR dan SSG. ```typescript // nuxt.config.ts // Konfigurasi lanjutan rendering hibrida export default defineNuxtConfig({ routeRules: { // Halaman marketing: di-pra-render dan disimpan dalam cache jangka panjang '/': { prerender: true }, '/pricing': { prerender: true }, '/features/**': { prerender: true }, // Blog: ISR (Incremental Static Regeneration) // Revalidasi setiap jam '/blog/**': { isr: 3600, prerender: true }, // Dokumentasi: cache CDN dengan revalidasi '/docs/**': { swr: 86400, // Stale-while-revalidate prerender: true }, // E-commerce: SSR dengan cache pendek '/products/**': { ssr: true, cache: { maxAge: 60, staleMaxAge: 300 } }, // Keranjang dan checkout: hanya sisi klien '/cart': { ssr: false }, '/checkout/**': { ssr: false }, // Dashboard: mode SPA '/dashboard/**': { ssr: false, // Menonaktifkan pra-rendering prerender: false }, // Route API: tanpa cache secara default '/api/**': { cors: true, headers: { 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE' } } } }) ``` Konfigurasi ini menggambarkan arsitektur khas aplikasi modern: halaman publik dioptimalkan untuk SEO dengan SSG, sementara bagian interaktif menggunakan rendering sisi klien. ## Optimasi performa dengan caching data Selain caching halaman, Nuxt 3 memungkinkan caching data yang diambil. Strategi ini mengurangi beban pada API dan meningkatkan waktu respons. ```typescript // server/api/articles/[slug].get.ts // Endpoint API dengan caching data import { getArticleBySlug } from '~/server/utils/articles' export default defineCachedEventHandler( async (event) => { const slug = getRouterParam(event, 'slug') if (!slug) { throw createError({ statusCode: 400, message: 'Slug tidak ada' }) } const article = await getArticleBySlug(slug) if (!article) { throw createError({ statusCode: 404, message: 'Artikel tidak ditemukan' }) } return article }, { // Kunci cache berdasarkan slug getKey: (event) => `article-${getRouterParam(event, 'slug')}`, // Durasi cache: 1 jam maxAge: 3600, // Stale-while-revalidate: menyajikan cache kedaluwarsa selama pembaruan staleMaxAge: 7200, // Invalidasi berbasis tag tags: ['articles'] } ) ``` Untuk menginvalidasi cache saat konten berubah, Nuxt menyediakan sistem tag. ```typescript // server/api/articles/[slug].put.ts // Pembaruan artikel dengan invalidasi cache import { updateArticle } from '~/server/utils/articles' export default defineEventHandler(async (event) => { const slug = getRouterParam(event, 'slug') const body = await readBody(event) // Memperbarui artikel const article = await updateArticle(slug, body) // Menginvalidasi cache untuk artikel ini await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`) // Atau invalidasi berbasis tag (semua artikel) // await useStorage('cache').clear('articles') return article }) ``` > **Cache terdistribusi** > > Di produksi dengan beberapa instance, cache dalam memori tidak mencukupi. Disarankan untuk mengonfigurasi Redis atau sistem terdistribusi lainnya melalui konfigurasi Nitro guna memastikan konsistensi antar instance. ## Pengelolaan SEO dan metadata SSR memungkinkan optimasi SEO dengan menghasilkan metadata di sisi server. Nuxt 3 menawarkan beberapa pendekatan untuk mengelola meta tag secara dinamis. ```vue ``` Untuk halaman statis, metadata dapat didefinisikan langsung di komponen. ```vue ``` ## Penerapan dan pertimbangan produksi Pilihan penerapan tergantung pada mode rendering yang digunakan. Berikut opsi utama dan konfigurasinya. ```typescript // nuxt.config.ts // Konfigurasi untuk berbagai lingkungan penerapan export default defineNuxtConfig({ nitro: { // Preset sesuai platform target // preset: 'vercel', // Vercel // preset: 'netlify', // Netlify // preset: 'cloudflare-pages', // Cloudflare // preset: 'node-server', // Node.js klasik // Konfigurasi untuk Node.js di produksi preset: 'node-server', // Kompresi respons compressPublicAssets: true, // Konfigurasi penyimpanan cache storage: { cache: { driver: 'redis', url: process.env.REDIS_URL } } }, // Variabel lingkungan runtime runtimeConfig: { // Rahasia (tidak diekspos ke klien) apiSecret: process.env.API_SECRET, // Konfigurasi publik public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api' } } }) ``` Untuk penerapan statis, perintah `npm run generate` membuat folder `.output/public` yang siap diterapkan di host file statis mana pun. ```bash # Generasi statis npm run generate # Konten .output/public dapat diterapkan ke: # - Vercel (deteksi otomatis) # - Netlify (konfigurasi otomatis) # - GitHub Pages # - S3 + CloudFront # - CDN atau server file statis apa pun ``` ## Kesimpulan Nuxt 3 menawarkan fleksibilitas luar biasa untuk merender aplikasi Vue.js. Pilihan antara SSR, SSG, dan rendering hibrida tergantung pada kebutuhan spesifik setiap proyek. **Poin-poin penting:** ✅ **SSR**: ideal untuk konten dinamis yang membutuhkan SEO yang baik (e-commerce, situs berita) ✅ **SSG**: sempurna untuk konten stabil (blog, dokumentasi, situs marketing) ✅ **Hibrida**: pendekatan terbaik untuk aplikasi kompleks dengan kebutuhan beragam ✅ **useFetch/useAsyncData**: hidrasi otomatis dan pengelolaan cache ✅ **routeRules**: konfigurasi terperinci untuk perilaku setiap route ✅ **Caching**: berbagai strategi untuk mengoptimalkan performa di produksi Menggabungkan rendering hibrida dengan strategi caching yang matang memungkinkan pembangunan aplikasi berkinerja tinggi yang dioptimalkan untuk SEO sambil tetap mempertahankan interaktivitas Single Page Applications. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/vue-nuxt/nuxt-3-ssr-static-generation