Episode ini membahas Vue Router: pendefinisian routes, dynamic dan nested routes dengan lazy loading, scroll behavior dan programmatic navigation, navigation guards, serta route meta untuk melindungi halaman sesuai kebutuhan autentikasi.

Aplikasi dengan satu halaman tidak cukup. Saat kalian butuh halaman beranda, halaman detail produk, dan halaman profil, kalian butuh routing — cara memetakan URL ke komponen. Vue Router adalah router resmi Vue dan tulang punggung navigasi single-page application.
Episode 9 membahas dari dasar: mendefinisikan routes, dynamic dan nested routes, lazy loading agar bundle tetap ramping, scroll behavior dan programmatic navigation, navigation guards, hingga route meta untuk autentikasi per rute.
Pasang Vue Router lalu definisikan tabel rute:
npm install vue-router@4import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/", name: "home", component: HomeView },
{ path: "/tentang", name: "tentang", component: AboutView },
],
});
export default router;createRouter({ history, routes }) membangun router; createWebHistory() memakai HTML5 History API sehingga URL bersih tanpa hash. Daftarkan router ke aplikasi dengan createApp(App).use(router).mount("#app").
Template menampilkan rute aktif lewat RouterView, dan navigasi memakai RouterLink:
<template>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/tentang">Tentang</RouterLink>
</nav>
<RouterView />
</template><RouterLink to="/"> dirender menjadi anchor dengan navigasi client-side tanpa reload, dan <RouterView /> menampilkan komponen rute yang sedang aktif.
Halaman detail biasanya punya URL seperti /produk/42; param-nya dibaca lewat route.params.id setelah useRoute() dipanggil di komponen:
const routes = [
{ path: "/produk/:id", name: "detail", component: ProductDetail },
];Saat param berubah, panggil fetching ulang dengan watch.
Route yang berisi sub-halaman diorganisasi dengan children:
const routes = [
{
path: "/akun",
component: AkunLayout,
children: [
{ path: "", component: AkunHome },
{ path: "pengaturan", component: AkunSetting },
],
},
];children dirender di dalam AkunLayout melalui <RouterView />. Cocok untuk halaman dengan tab atau sidebar yang layout-nya sama.
Jangan impor semua halaman sekaligus; gunakan dynamic import agar tiap halaman di-fetch terpisah:
const routes = [
{
path: "/produk/:id",
component: () => import("../views/ProductDetail.vue"),
},
];component: () => import(...) memuat halaman hanya saat dibuka, membagi kode per route — fondasi code splitting yang diperdalam di episode 14.
Guard berjalan sebelum navigasi diselesaikan. Contoh paling umum: cek autentikasi:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLogin()) {
next({ name: "login", query: { redirect: to.fullPath } });
} else {
next();
}
});to.meta.requiresAuth membaca meta rute tujuan; jika butuh login, alihkan ke halaman login dengan redirect kembali.
Navigasi juga bisa dipicu dari kode dengan useRouter(), misalnya router.push({ name: "detail", params: { id } }) setelah tombol diklik, atau router.back() untuk menyamai tombol kembali browser.
Saat pindah halaman, scrollBehavior(to, from, savedPosition) di konfigurasi router mengembalikan posisi scroll: pakai savedPosition saat kembali dari history, atau { top: 0 } untuk navigasi baru.
Agar komponen tidak bergantung useRoute, aktifkan props mode: { path: "/produk/:id", component: ProductDetail, props: true }. Dengan props: true, :id diteruskan langsung sebagai prop id sehingga komponen bersih dan mudah diuji.
Route meta bisa membawa data kebijakan, seperti siapa yang boleh membuka halaman:
const routes = [
{
path: "/admin",
component: AdminView,
meta: { requiresAuth: true, roles: ["admin"] },
},
];Guard lalu membaca meta untuk menegakkan kebijakan: jika to.meta.roles tidak memuat role user, arahkan ke halaman forbidden. to.meta.roles.includes(roleUser()) memeriksa apakah role user ada dalam daftar yang diizinkan — dasar role-based access yang dibangun lengkap di episode 12.
Info
Semua logika keamanan rute di client hanya kenyamanan UI. Validasi sesungguhnya tetap harus dilakukan di server — berlaku untuk semua episode security selanjutnya.
Episode 9 membawa kalian dari satu halaman ke aplikasi multi-halaman: definisi routes dengan createRouter, dynamic dan nested routes, lazy loading per rute, programmatic navigation, scroll behavior, route props, serta meta dan guards untuk kebijakan akses per rute.
Inti yang harus dibawa pulang:
RouterView menampilkan rute; RouterLink menavigasi tanpa reload.:id dibaca lewat route.params.children membentuk nested routes dengan layout bersama.() => import(...).beforeEach cocok untuk cek autentikasi.Di episode 10 selanjutnya kita membahas state management modern — Pinia sebagai store resmi Vue, definisi stores dengan state, getters, dan actions, plugin Pinia, serta best practices untuk normalisasi state dan modular stores pada aplikasi berskala besar.