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-vitalsuntuk 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.vueataunuxt.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.manualChunksatauviteuntuk 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
lodashseluruh modul; gunakanlodash-esatau fungsi spesifik. - Gunakan
dynamic importuntuk 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:
- Server render lambat: Terlalu banyak data fetch synchronous menyebabkan response lambat, memengaruhi LCP.
- Hydration terlalu besar: Semua komponen di-serialize ke client. Jika bundle besar, interaksi pertama menunggu JS hydrate.
- Data fetching tidak efisien: Use
useAsyncDatadengan 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
sizesdanquality. - 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.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!