Bayangkan kamu membangun rumah megah — desain keren, furniture mewah, taman indah. Tapi saat tamu datang, pintu masuknya sempit dan tangga-nya lambat. Hasilnya? Tamu frustrasi dan langsung balik kanan. Persis seperti itu kondisi aplikasi Vue 3 yang tidak dioptimasi. Fitur lengkap, tapi lambat — dan pengguna kabur sebelum sempat menikmatinya.
Di artikel ke-14 dari seri Vue from Zero to Zorro ini, kita akan membahas performa Vue 3 secara praktis: mulai dari lazy loading Vue, code splitting, hingga best practice Vue 3 yang langsung bisa kamu terapkan hari ini. Ini bukan teori kosong — setiap teknik di sini sudah teruji dan dipakai di production.
Siap bikin aplikasi kamu terbang? Mari mulai! 🚀
Aplikasi yang bagus bukan hanya yang bisa berjalan, tapi yang berjalan cepat, ringan, dan nyaman di semua kondisi jaringan. Vue 3 memberikan alat yang luar biasa — tugas kita adalah memakainya dengan benar.
01. Lazy Loading Vue — Muat Hanya Yang Dibutuhkan
Analogi: kamu lagi belanja di supermarket. Apakah kamu langsung ambil semua barang di rak begitu masuk? Tentu tidak — kamu ambil hanya yang kamu butuhkan saat itu. Lazy loading bekerja persis seperti itu pada aplikasi Vue 3: komponen dan halaman hanya dimuat saat benar-benar dibutuhkan pengguna.
Tanpa lazy loading, browser kamu memuat semua JavaScript di awal — meski pengguna hanya mengunjungi satu halaman. Hasilnya: loading pertama lambat, pengguna ilfeel, dan bounce rate meroket.
Menurut Google, setiap 100ms keterlambatan loading dapat menurunkan konversi hingga 7%. Artinya, performa bukan sekadar teknis — ini soal uang dan pengguna.
Lazy Loading Komponen dengan defineAsyncComponent
Vue 3 menyediakan defineAsyncComponent untuk memuat komponen secara lazy. Contoh langsung:
import { defineAsyncComponent } from 'vue' // ✅ Komponen ini TIDAK dimuat saat aplikasi pertama jalan // Hanya dimuat saat komponen benar-benar dirender const HeavyDashboard = defineAsyncComponent(() => import('./components/HeavyDashboard.vue') ) // ✅ Dengan loading state dan error handling const SmartComponent = defineAsyncComponent({ loader: () => import('./components/SmartComponent.vue'), loadingComponent: LoadingSpinner, // tampil saat loading errorComponent: ErrorDisplay, // tampil saat error delay: 300, // delay sebelum loading state timeout: 5000 // timeout jika gagal load })
Lazy Loading Route di Vue Router
Ini adalah teknik paling umum dan paling berdampak. Setiap halaman hanya dimuat saat pengguna mengunjunginya:
const routes = [ { path: '/', // ✅ HomeView dimuat lazy — bukan import biasa di atas component: () => import('../views/HomeView.vue') }, { path: '/dashboard', // ✅ Dashboard hanya dimuat saat user buka /dashboard component: () => import('../views/DashboardView.vue') }, { path: '/profile', // ✅ Named chunk — berguna untuk debugging bundle component: () => import(/* webpackChunkName: "profile" */ '../views/ProfileView.vue') } ]
Gunakan webpackChunkName (atau Vite rollupOptions) untuk memberi nama pada chunk. Ini mempermudah debugging di DevTools dan memastikan file chunk mudah diidentifikasi saat production build.
02. Code Splitting — Pecah Besar Jadi Kecil-Kecil
Analogi lagi: daripada mengirim satu koper besar yang berat ke tamu, lebih baik kirim beberapa tas kecil — ringan, cepat sampai, dan tamu bisa pakai duluan sambil nunggu yang lain. Code splitting memecah bundle JavaScript besar menjadi chunk-chunk kecil yang dimuat sesuai kebutuhan.
Vue 3 dengan Vite (atau Webpack) mendukung code splitting otomatis via dynamic import. Tapi kamu bisa mengontrolnya lebih lanjut:
export default defineConfig({ build: { rollupOptions: { output: { // ✅ Pisahkan vendor library dari kode aplikasi manualChunks: { 'vue-vendor': ['vue', 'vue-router', 'pinia'], 'ui-libs': ['@headlessui/vue', 'lucide-vue-next'], 'utils': ['axios', 'dayjs', 'lodash-es'] } } } } })
Memisahkan vendor chunk (vue, vue-router, dll.) dari kode aplikasi sangat penting karena library ini jarang berubah. Browser bisa meng-cache vendor chunk lebih lama, sehingga deploy baru tidak memaksa pengguna re-download semua aset.
03. Best Practice Vue 3 — Kebiasaan yang Membedakan Junior dan Senior
Kode yang bekerja dan kode yang baik adalah dua hal berbeda. Best practice Vue 3 bukan soal aturan kaku — ini soal kebiasaan yang bikin kode kamu mudah dibaca, mudah di-maintain, dan tentunya lebih performant.
Gunakan v-memo untuk List Besar
Directive v-memo adalah fitur Vue 3.2+ yang mencegah re-render komponen di dalam list jika dependency tidak berubah.
<!-- ✅ Hanya re-render jika item.id atau selected berubah --> <div v-for="item in list" :key="item.id" v-memo="[item.id, selected === item.id]"> {{ item.name }} </div>
Manfaatkan computed dan Hindari Logic di Template
Computed property di-cache berdasarkan dependency-nya. Jangan taruh logika berat langsung di template — ini bikin Vue re-hitung setiap render.
// ❌ Buruk: logika berat di template <!-- {{ users.filter(u => u.active).sort(...).slice(0, 10) }} --> // ✅ Baik: gunakan computed const topActiveUsers = computed(() => users.value .filter(u => u.active) .sort((a, b) => b.score - a.score) .slice(0, 10) )
Selalu Gunakan :key yang Unik dan Stabil
Vue menggunakan :key untuk mengidentifikasi elemen di virtual DOM. Key yang salah = bug aneh yang susah dilacak.
// ❌ Buruk: pakai index sebagai key <li v-for="(item, index) in items" :key="index"> // ✅ Baik: pakai ID unik dari data <li v-for="item in items" :key="item.id">
Cleanup di onUnmounted — Hindari Memory Leak
Event listener, interval, atau subscription yang tidak di-cleanup akan menyebabkan memory leak parah, terutama di SPA (Single Page Application).
import { onMounted, onUnmounted } from 'vue' const handleResize = () => { /* ... */ } onMounted(() => { window.addEventListener('resize', handleResize) }) // ✅ Wajib cleanup saat komponen di-unmount! onUnmounted(() => { window.removeEventListener('resize', handleResize) })
Gunakan shallowRef dan shallowReactive untuk Data Besar
ref() dan reactive() membuat semua nested property reaktif — mahal untuk objek besar. Gunakan versi shallow jika kamu tidak butuh deep reactivity.
import { shallowRef, shallowReactive } from 'vue' // ✅ Untuk array/objek besar yang hanya butuh reaktivitas di level atas const bigDataset = shallowRef([]) const config = shallowReactive({ theme: 'dark', lang: 'id' })
Jangan gunakan v-if dan v-for pada elemen yang sama. Ini menyebabkan Vue memproses v-for dulu baru v-if, yang bisa jadi bug tersembunyi. Gunakan <template v-for> dengan v-if di dalam, atau gunakan computed yang sudah difilter.
04. Performa Vue 3 — Ringkasan Teknik & Kapan Pakainya
Banyak teknik yang bisa dipakai, tapi tidak semuanya relevan di setiap situasi. Berikut ringkasan kapan harus memakai teknik apa:
| Teknik | Kapan Dipakai | Dampak |
|---|---|---|
| Lazy Route Loading | Semua aplikasi multi-halaman | ⭐⭐⭐ Tinggi |
| defineAsyncComponent | Komponen berat / jarang tampil | ⭐⭐⭐ Tinggi |
| computed property | Kalkulasi yang bergantung state | ⭐⭐ Menengah |
| v-memo | List panjang dengan kondisi tertentu | ⭐⭐ Menengah |
| shallowRef/shallowReactive | Objek/array besar tanpa deep reactivity | ⭐⭐ Menengah |
| manualChunks (Vite) | Production build dengan banyak vendor lib | ⭐⭐⭐ Tinggi |
Jika kamu baru memulai optimasi, lakukan dalam urutan ini agar effort minimum, dampak maksimum:
- Lazy loading semua route — dampak paling besar, mudah dilakukan
- Pisahkan vendor chunks — optimalkan cache browser
- Pindahkan logika ke computed — kode lebih bersih sekaligus performant
- Cleanup event listener — cegah memory leak sebelum jadi masalah
- v-memo dan shallowRef — hanya jika profiling menunjukkan bottleneck
Jangan optimasi yang belum bermasalah. Gunakan Vue DevTools (tab Performance) dan Lighthouse untuk mengidentifikasi bottleneck nyata. Optimasi prematur adalah akar dari semua kejahatan — kata Donald Knuth, dan ini berlaku di Vue juga.
No comments:
Post a Comment