Pendahuluan

Core Web Vitals (CWV) menjadi tolok ukur kritikal untuk pengalaman pengguna. Nuxt 3 sebagai framework Vue 3 berbasis server-side rendering (SSR) dan client-side hydration memiliki potensi tinggi untuk mencapai skor tinggi jika dipoles dengan pendekatan performa yang tepat. Artikel ini membahas langkah praktis untuk mengoptimalkan Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), dan Interaction to Next Paint (INP) di Nuxt 3.

Fokusnya mencakup pengerahan teknik lazy loading komponen, optimasi gambar lewat @nuxt/image, code splitting, prefetch/preload, pengurangan JavaScript tidak perlu, caching aset, serta penyelidikan bottleneck SSR/ hydration. Setiap pendekatan disertai alasan mengapa efektif dan bagaimana menerapkannya dengan kode riil.

Mengukur Performa: Lighthouse dan Web Vitals

Sebelum mengoptimasi, identifikasi baseline performa. Gunakan dua alat utama:

  • Lighthouse DevTools: Tekan F12 > tab Lighthouse > pilih Device (Mobile/ Desktop) > Generate report. Fokus pada nilai Core Web Vitals dan lihat audit terkait Largest Contentful Paint, Cumulative Layout Shift, dan Total Blocking Time (pengukur INP/CLS).
  • Web Vitals Extension atau Web Vitals library: Gunakan web-vitals untuk menangkap metrik nyata di lingkungan nyata (RUM). Ekspor data ke log atau service monitoring untuk melihat tren LCP/CLS/INP.

Catatan: Nilai di Lighthouse cenderung lebih konservatif, sedangkan Web Vitals memberi gambaran pengguna akhir. Gunakan keduanya untuk triangulasi masalah.

Optimasi LCP

Pentingnya memuat isi utama lebih cepat

LCP mengukur waktu render elemen terbesar di viewport awal (biasanya hero image atau judul). Strategi utama:

  • Preload sumber daya kritikal: Preload font utama, gambar hero, atau CSS kritis. Tambahkan di app.vue atau nuxt.config.ts:
export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'preload', href: '/fonts/Inter.woff2', as: 'font', type: 'font/woff2', crossorigin: 'anonymous' },
        { rel: 'preload', href: '/images/hero.jpg', as: 'image' }
      ]
    }
  }
})

Preload membantu browser menempatkan prioritas request sehingga LCP element tidak tertunda.

Lazy loading komponen berat

Komponen non-kritis bisa dimuat dengan dynamic import agar tidak membebani batas payload awal. Gunakan Nuxt defineNuxtComponent atau defineAsyncComponent:

const FeatureGrid = defineAsyncComponent(() => import('@/components/FeatureGrid.vue'))

export default {
  components: { FeatureGrid }
}

Penggunaan ini memastikan HTML utama (termasuk LCP) dirender tanpa menunggu bundle tambahan.

Optimasi CLS

Kontrol layout shift

CLS terjadi saat elemen bergeser tiba-tiba. Untuk Nuxt 3:

  • Definisikan dimensi gambar dan video agar browser bisa mengatur ruang sebelum asset selesai dimuat.
  • Gunakan placeholder SVG atau CSS untuk area konten dinamis.
  • Hindari menyisipkan iklan atau iframe tanpa reservasi ruang.

Contoh: Gunakan kelas CSS dengan rasio aspek:

.aspect-ratio-box {
  position: relative;
  width: 100%;
  padding-top: 56.25%;
}
.aspect-ratio-box > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Ima gen hero di Nuxt:

<div class="aspect-ratio-box">
  <NuxtImage src="/images/hero.jpg" alt="Hero" width="1200" height="675" />
</div>

Optimasi INP

Kurangi blocking JavaScript

INP (Interaction to Next Paint) bergantung pada berapa lama event handler memblokir rendering lanjutan. Strategi:

  • Pisahkan aplikasi ke chunk lebih kecil: Manfaatkan fitur build.rollupOptions.output.manualChunks atau vite untuk memecah logika tidak kritis.
  • Kurangi dependensi berat: Hindari paket bundel besar di halaman awal. Gunakan import() untuk memuat modul secara bertahap.
  • Gunakan event delegation ringan: Hindari listener global yang men-trigger parsing heavy.

Lazy loading interaksi

Jika ada modal atau komponen interaktif berat, render skeleton di awal, lalu import komponen saat pengguna akan berinteraksi:

const Modal = defineAsyncComponent(() => import('@/components/Modal.vue'))

function openModal() {
  ModalLoader.value = Modal
}

Dengan menunda loading sampai diperlukan, thread utama lebih lega untuk mengejar INP yang baik.

Optimasi Teknologi Khusus Nuxt 3

Lazy loading komponen dan modul Nuxt

Gunakan defineNuxtComponent dengan defineAsyncComponent agar komponen berat tidak ditambahkan ke bundle awal. Tambahkan v-if atau client-only jika komponen hanya perlu di client.

Optimasi gambar dengan @nuxt/image

Module image Nuxt menyediakan transformasi otomatis dan format modern:

export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    providers: {
      static: {
        provider: 'static',
        options: { sizes: [320, 640, 1024], formats: ['webp', 'avif'] }
      }
    }
  }
})

Gunakan <NuxtImage> agar ukuran, quality, dan format otomatis dioptimasi, membantu LCP dan CLS karena ukuran sudah didefinisikan.

Code splitting dan prefetch/preload

Manfaatkan Nuxt Turbo Modules:

  • Auto-import components: Jika Anda menggunakan components: true, Nuxt akan memecah komponen per rute.
  • Prefetch link: Gunakan <NuxtLink prefetch> untuk memuat resource rute selanjutnya saat idle.
  • Preload asset kritikal: Seperti hero image atau CSS kritikal, tambahkan di app.vue.

Contoh manual code splitting:

const HeavyChart = () => import('@/components/HeavyChart.vue')

export default {
  components: { HeavyChart },
  mounted() {
    HeavyChart()
  }
}

Kurangi JavaScript tidak perlu (tree shaking dan treeshake-aware libraries)

Periksa bundle dengan Vite Analyzer (npm run analyze) dan hapus polyfill/useless utilities. Beberapa langkah:

  • Gunakan util berbasis ES modules untuk tree shaking lebih maksimal.
  • Hindari import dari lodash seluruh modul; gunakan lodash-es atau fungsi spesifik.
  • Gunakan dynamic import untuk util hanya dipakai saat interaksi tertentu.

Cache aset secara agresif

Tambahkan header caching di server (baik Nuxt Nitro atau CDN). Contoh konfigurasi Nitro untuk caching:

export default defineNitroConfig({
  routeRules: {
    '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } }
  }
})

Penting: Jangan cache HTML SSR terlalu lama karena konten dinamis. Gunakan stale-while-revalidate untuk menyeimbangkan performa dan keakuratan data.

Bottleneck Umum pada SSR dan Hydration

Nuxt 3 menggunakan SSR + hydration. Beberapa sumber bottleneck:

  1. Server render lambat: Terlalu banyak data fetch synchronous menyebabkan response lambat, memengaruhi LCP.
  2. Hydration terlalu besar: Semua komponen di-serialize ke client. Jika bundle besar, interaksi pertama menunggu JS hydrate.
  3. Data fetching tidak efisien: Use useAsyncData dengan caching, hindari fetch duplicate.

Debug: Gunakan nuxt devtools untuk melihat waktu render server vs hydration, dan Performance tab di Chrome DevTools untuk melihat long tasks.

Checklist Optimasi Core Web Vitals Nuxt 3

  • Pengukuran: Jalankan Lighthouse & Web Vitals RUM untuk baseline LCP/CLS/INP.
  • LCP: Preload asset kritikal, lazy load komponen non-kritis, optimasi layout hero image dengan Nuxt Image.
  • CLS: Tetapkan dimensi untuk semua media, gunakan placeholder rasio aspek, hindari perubahan layout mendadak.
  • INP: Pisahkan bundle, kurangi event blocking, lazy load interaksi berat.
  • Gambar: Aktifkan provider Nuxt Image dengan format modern, set sizes dan quality.
  • JS: Pakai dynamic import, tree shaking, kurangi dependensi tidak terpakai.
  • Caching: Cache aset statis dengan header immutable, gunakan route rules Nitro.
  • Bottleneck SSR: Profil render server, batasi data fetch synchronous, gunakan streaming jika memungkinkan.
  • Prefetch/Preload: Preload font/gambar LCP, prefetch rute berikutnya.
  • Monitoring: Pasang alert Web Vitals (misal CrUX data) untuk melihat regresi.

Kesimpulan

Optimasi Core Web Vitals pada Nuxt 3 butuh kombinasi pengukuran yang tepat, kontrol rendering SSR, serta teknik optimasi asset dan JavaScript. Dengan pendekatan lazy loading, code splitting, optimasi gambar, prefetch/preload, serta caching aset, LCP, CLS, dan INP bisa ditingkatkan secara signifikan. Gunakan checklist di atas sebagai panduan tindakan nyata, lalu terus pantau metrik via Lighthouse/Web Vitals untuk memastikan setiap perubahan berdampak positif.