Async Components — Vue

defineAsyncComponent const HeavyComponent = defineAsyncComponent( () => import("./HeavyComponent.vue") ) ---template--- Konten async dimuat Memuat... Async…

Async component adalah komponen yang kodenya baru diunduh saat pertama kali dibutuhkan, bukan ikut di unduhan awal halaman. Vue membuatnya dengan defineAsyncComponent(). Bayangin buku riwayat pesanan Warung Bu Sri: tebal dan jarang dibuka. Bu Sri gak membawanya ke meja kasir tiap pagi. Buku itu disimpan di gudang dan baru diambil saat ada pembeli yang menanyakan pesanan lamanya. Pertama kali butuh waktu sebentar untuk mengambilnya; sesudah itu bukunya sudah di meja.

🧪 Tebakan cepat: RiwayatPesanan dibuat dengan defineAsyncComponent dan diberi loadingComponent bertuliskan "Memuat riwayat...", tanpa opsi delay. Unduhannya selesai dalam 150 ms. Apakah "Memuat riwayat..." sempat tampil? Tebak dulu, jawabannya ada di bagian "Loading, error, delay, timeout".

defineAsyncComponent: diunduh saat pertama dirender

<script setup>
import { ref, defineAsyncComponent } from "vue"

const RiwayatPesanan = defineAsyncComponent(() => import("./RiwayatPesanan.vue"))
const buka = ref(false)
</script>

<template>
  <button @click="buka = !buka">Riwayat pesanan</button>
  <RiwayatPesanan v-if="buka" />
</template>
Kejadian Yang diunduh Yang tampil
Halaman dibuka bundle utama saja tombol Riwayat pesanan
Klik pertama file terpisah, misalnya RiwayatPesanan-a1b2c3.js belum ada apa-apa sampai unduhannya selesai
Unduhan selesai gak ada daftar riwayat
Tutup, lalu buka lagi gak ada, sudah tersimpan daftar riwayat, langsung
const buka = ref(false)
const RiwayatPesanan = Vue.defineAsyncComponent(() =>
  new Promise((resolve) => {
    setTimeout(() => resolve({ template: "<ul><li>Nasi Goreng Rp15000</li></ul>" }), 1000)
  })
)

---template---
<button @click="buka = !buka">Riwayat pesanan</button>
<component v-if="buka" :is="RiwayatPesanan" />

Loading, error, delay, timeout

Selama mengunduh, async component gak menampilkan apa-apa. Untuk memberi tahu pembeli, pakai bentuk objek:

const RiwayatPesanan = defineAsyncComponent({
  loader: () => import("./RiwayatPesanan.vue"),
  loadingComponent: MemuatRiwayat,   // tampil selama mengunduh
  delay: 200,                        // bawaan: tunggu 200 ms dulu sebelum loadingComponent tampil
  errorComponent: GagalMemuat,       // tampil kalau unduhannya gagal
  timeout: 3000,                     // dianggap gagal kalau lewat 3 detik
})
Unduhan Yang tampil
selesai dalam 150 ms kosong sebentar, lalu daftar riwayat. "Memuat riwayat..." gak sempat tampil
selesai dalam 1,5 detik kosong 200 ms, lalu "Memuat riwayat...", lalu daftar riwayat
gagal "Riwayat gagal dimuat" dari errorComponent; tanpa errorComponent, tempatnya tetap kosong, atau "Memuat riwayat..." gak pernah hilang. Error-nya selalu ditulis di console
1,5 detik dengan timeout: 1000 errorComponent di detik pertama, lalu daftar riwayat saat unduhannya akhirnya selesai

Jawaban tebakannya: gak sempat. Itu jawaban tebakannya. delay bawaannya 200 ms, dan unduhan 150 ms sudah selesai sebelum itu. Delay ini sengaja: di koneksi cepat, tulisan loading yang muncul sekejap lalu hilang malah terasa seperti kedipan. Tulis delay: 0 kalau loading harus langsung tampil.

Suspense: satu fallback untuk yang async

Komponen yang setup-nya menunggu sesuatu, misalnya <script setup> dengan await di baris paling atas, disebut komponen dengan async setup. Ia harus dibungkus <Suspense>:

<!-- RiwayatPesanan.vue -->
<script setup>
const res = await fetch("/api/riwayat")
const daftar = await res.json()
</script>

<!-- App.vue -->
<template>
  <Suspense>
    <RiwayatPesanan />
    <template #fallback>
      <p>Memuat riwayat...</p>
    </template>
  </Suspense>
</template>

⚠️ Jebakan yang sering ketemu

TL;DR: defineAsyncComponent(() => import("./RiwayatPesanan.vue")) membuat komponen yang kodenya diunduh terpisah saat pertama dirender, lalu disimpan; itu code splitting, dan bundle awal jadi lebih kecil. Bentuk objeknya menambah loadingComponent (tampil sesudah delay, bawaan 200 ms), errorComponent, dan timeout. <Suspense> dengan slot #fallback menunggu komponen dengan async setup dan async component di dalamnya; tanpa Suspense, async setup gak pernah tampil. Pakai async component untuk bagian yang besar dan jarang dipakai.

Yang akan kamu pelajari