Membedah routing dan navigasi di arsitektur microfrontend: host memegang route top-level, remote merender isi halaman, lazy load dengan React.lazy dan Suspense, deep linking dari server, serta pola whitespace prefix untuk menghindari konflik route antara host dan remote.

Setelah memahami shared dependencies di episode 5, kita masuk ke bagian yang langsung terasa oleh user: navigasi. Dalam microfrontend, pertanyaan "siapa yang mengendalikan URL?" adalah keputusan arsitektur paling mendasar — dan paling sering disalahpahami.
Mengapa penting? Karena user tidak peduli dengan batas remote — mereka hanya melihat satu situs. Jika routing berantakan, user akan tersesat di URL yang salah, halaman tidak bisa di-deep-link, atau refresh malah 404. Episode ini membahas cara shell mengelola rute agar pengalaman terasa mulus meski di balik layar terdiri dari banyak aplikasi.
Dalam arsitektur kita, shell adalah satu-satunya yang tahu bentuk URL publik. Shell mendefinisikan route top-level:
import { createBrowserRouter } from 'react-router-dom'
import App from './App'
const router = createBrowserRouter([
{ path: '/', element: <App /> },
{ path: '/catalog', element: <LazyRemote url={import('catalog/CatalogApp')} /> },
{ path: '/cart', element: <LazyRemote url={import('cart/CartApp')} /> },
{ path: '/product/:id', element: <LazyRemote url={import('product-detail/ProductApp')} /> },
])Perhatikan: shell tidak meng-implementasi isi katalog atau cart — ia hanya tahu ke mana rute menunjuk dan remote mana yang merender isinya.
Host menulis komponen kecil LazyRemote yang memuat module remote sesuai rute:
import { Suspense, lazy, type ComponentType } from 'react'
export function LazyRemote({
loader,
}: {
loader: () => Promise<{ default: ComponentType }>
}) {
const Comp = lazy(loader)
return (
<Suspense fallback={<p>Memuat halaman...</p>}>
<Comp />
</Suspense>
)
}Jadi host menyediakan kerangka (shell + loading) dan remote mengisi konten.
Remote boleh punya router internal sendiri untuk navigasi di dalam domainnya. Contoh: catalog punya filter dan pagination yang mengubah URL /catalog?page=2 — ini urusan internal catalog. Namun route publik (path top-level) tetap dikelola shell.
Prinsipnya: remote tahu cara menavigasi di dalam wilayahnya; shell tahu cara menavigasi antar wilayah.
Agar tidak memuat semua remote di awal, host memuat remote secara lazy per route — hanya remote untuk rute yang sedang aktif yang di-load. React.lazy + Suspense (yang kita pakai sejak episode 4) adalah caranya. Ini menjaga bundle awal host kecil dan hanya memuat katalog saat user benar-benar mengunjungi /catalog. Detail performa dan preloading kita bahas di episode 12.
Deep linking berarti URL ke rute di dalam remote harus bisa diakses langsung (di-bookmark atau di-refresh) dan tetap menampilkan halaman yang benar. Masalahnya muncul pada URL dengan path dalam remote seperti /product/abc-123.
Agar berfungsi, server hosting host harus punya history fallback: semua path yang tidak cocok dengan file statis diarahkan ke index.html host, sehingga React Router bisa menangani path tersebut. Tanpa ini, refresh di /product/abc-123 akan menghasilkan 404 dari server.
// konfigurasi server Anda (nginx/Vercel/Node) harus:
// /product/* -> index.html (fallback SPA)Bahaya terbesar: host dan remote mendefinisikan route yang bentrok. Contoh, host sudah punya /cart, dan remote cart juga mendefinisikan /cart secara keras — terjadi konflik.
Solusinya adalah menetapkan prefix unik per remote dan menaatinya. Shell memegang route top-level; remote hanya berasumsi rute mereka berada di bawah prefix tertentu:
| Remote | Root Prefix |
|---|---|
| catalog | /catalog |
| product-detail | /product/:id |
| cart | /cart |
| checkout | /checkout |
| account | /account |
Dengan aturan ini, remote tidak perlu "tahu" rute milik remote lain, dan tidak ada dua aplikasi yang mengklaim path yang sama.
Important
Komunikasikan prefix route sebagai bagian dari kontrak antar remote (kita bahas kontrak ini di episode 17). Jika sebuah remote pindah prefix, seluruh deep link dan referensi lintas remote ikut berubah — harus dikelola sebagai breaking change.
Pada episode 6 ini, kalian telah memahami routing & navigasi di microfrontend.
Inti yang harus dibawa pulang:
React.lazy + Suspense agar bundle awal kecil.Di episode 7 selanjutnya, kita akan membahas global state & auth (shared across remotes) — bagaimana remote tahu user login, role, dan cart count tanpa menduplikasi state, lewat event bus, central store, dan sharing token. Pastikan remote kalian sudah bisa dinavigasi!