Jujur saja, saya sempat berada di titik jenuh dengan Single Page Application (SPA).

Bayangkan skenarionya: Anda membangun website portofolio atau blog sederhana menggunakan Create React App (CRA) atau bahkan Next.js. Semuanya terasa modern dan canggih di awal. Tapi begitu konten mulai banyak, skor Lighthouse mulai merah merona. Bundle JavaScript membengkak, dan Time to Interactive (TTI) makin lambat.

“Masa iya buat baca artikel doang harus download React 50KB?” pikir saya waktu itu.

Lalu saya bertemu Astro. Dan percayalah, ini adalah “angin segar” yang saya tunggu-tunggu.

Mengapa Pindah Hati?

Sebelum kita masuk ke teknis, mari kita bicara “Why”. Kenapa repot-repot rewrite ulang?

Di kasus saya, masalah utamanya adalah Client-side Hydration yang berlebihan. Di React SPA, seluruh halaman adalah JavaScript. Di Astro, HTML adalah raja. Strategi ini disebut Islands Architecture.

FiturReact SPAAstro
Rendering StrategyClient-side / HybridServer-first (Static)
JS Bundle SizeBesar (Runtime + App)Nol (Default)
HydrationFull PagePartial (Islands)
Learning CurveMenengahRendah (HTML-first)
Hasil Akhir Spoiler

Setelah migrasi, First Contentful Paint (FCP) website ini turun dari 1.8s menjadi 0.3s. Tanpa trik aneh-aneh. Murni arsitektur.

TODO: Screenshot skor Lighthouse 100/100

Arsitektur: SPA vs Islands

Perbedaan fundamentalnya ada di sini. React mencoba mengontrol segalanya. Astro membiarkan HTML menjadi HTML, dan hanya memanggil JavaScript saat ada interaksi (seperti slider atau tombol like). Ini adalah visualisasi perbedaannya:

Perbandingan Flow Rendering: React SPA memaksa user menunggu JS, Astro langsung interaktif.
graph TD
  subgraph ReactSPA ["React SPA"]
      A["index.html Kosong"] --> B["Load Bundle JS Raksasa"]
      B --> C["Render Seluruh Halaman"]
      C --> D["Hydrate Semuanya"]
  end
  subgraph AstroApp ["Astro"]
      E["Server Render HTML"] --> F["Tampil Langsung"]
      F --> G{"Ada Interaksi?"}
      G -- Ya --> H["Load JS Kecil (Island)"]
      G -- Tidak --> I["Zero JS"]
  end
  style H fill:#d1fae5,stroke:#059669

Langkah-Langkah Migrasi

Oke, cukup teorinya. Mari kita kotor-kotoran dengan kode. Ini adalah workflow yang saya gunakan saat migrasi aplikasi portofolio saya.

1. Setup Project Astro

Lupakan konfigurasi Webpack yang bikin sakit kepala. Astro punya wizard super sakti.

Terminal
npm create astro@latest my-new-blog

Saat ditanya “Include sample files?”, saya sarankan pilih Empty agar kita paham strukturnya dari nol. Folder structure Astro sangat mirip dengan Next.js Pages Router, jadi React developer pasti langsung familiar dengan folder src/pages.

2. Integrasi React

“Tunggu, berarti kode React saya harus dibuang?”

Tentu tidak! Ini bagian terbaiknya. Kita bisa pakai komponen React yang sudah ada langsung di dalam Astro. Cukup tambahkan integrasinya:

Terminal
npx astro add react

Astro akan otomatis mengupdate astro.config.mjs Anda. Semudah itu. Anda bisa langsung mengimport mainan lama Anda seperti Button.jsx atau Card.jsx.

3. Pindahkan Komponen UI

Saya mulai dengan memindahkan komponen “bodoh” (presentational) seperti Header, Footer, dan Card.

Di React (Next.js), kita mungkin punya components/Navbar.jsx. Di Astro, kita bisa rename jadi components/Navbar.astro dan sesuaikan sedikit sintaksnya.

Perbandingan Sintaks
tsx
// React Component (Navbar.jsx) export default function Navbar({ title }) { return <h1>{title}</h1>; } // Astro Component (Navbar.astro) --- const { title } = Astro.props; --- <h1>{title}</h1>

Lihat? Bagian atas Astro (frontmatter) itu wajar banget buat JS developer. Rasanya seperti menulis PHP tapi modern (jangan bully saya). Keuntungannya? Kode di area frontmatter tidak akan dikirim ke browser. Rahasia aman.

4. The “Island” Magic

Ini bagian critical. Di Astro, komponen React tidak akan jalan JavaScript-nya (interactivity mati) kecuali kita beritahu secara eksplisit.

Misalnya saya punya komponen <SearchBar /> yang butuh state React untuk filter list.

Salah (Halaman jadi statis doang):

<SearchBar />

Benar (Hydrate saat load):

<SearchBar client:load />

Atau biar makin geeky, pakai client:visible. JS-nya baru didownload pas user scroll sampai ke komponen itu. Mind blown, kan? 🤯 Ini menghemat bandwidth user secara signifikan.

TODO: Screenshot browser devtools network tab

Tantangan yang Dihadapi (Solusi Teknis)

Gak adil kalau cuma ngomong manisnya. Ada beberapa hal yang bikin garuk kepala saat migrasi, tapi untungnya solusinya elegan.

1. Global State Management

Di React SPA saya biasa pakai Context API di root untuk tema atau cart. Di Astro, karena setiap halaman itu terisolasi (MPA), sharing state antar halaman jadi tricky. Context React tidak bisa lintas halaman Astro.

Solusi: Saya menggunakan Nano Stores. Library state management super ringan yang framework-agnostic.

store/cart.ts
ts
import { atom } from 'nanostores'; export const isCartOpen = atom(false); // Bisa dipakai di React Component import { useStore } from '@nanostores/react'; // Bisa dipakai di Svelte, Vue, atau script biasa!

2. Navigasi SPA (View Transitions)

User React terbiasa dengan transisi halaman yang instan tanpa refresh putih (blink).

Solusi: Untungnya, Astro 3.0+ punya View Transitions API native. Cukup tambah 2 baris kode di Layout.astro Anda:

Layout.astro
astro
import { ViewTransitions } from 'astro:transitions'; <head> <ViewTransitions /> </head>

Boom! Halaman Anda sekarang navigasinya sehalus SPA, tapi arsitekturnya tetap MPA yang ringan.

Kesimpulan: Worth It?

1000% Yes.

Untuk website konten seperti blog, dokumentasi, atau portofolio, bertahan di React SPA itu seperti membunuh nyamuk pakai bazooka. Keren sih, tapi berat dan overkill. Pengunjung website Anda tidak peduli seberapa canggih stack Anda, mereka peduli seberapa cepat konten muncul.

Dengan Astro, saya dapat DX (Developer Experience) ala React, tapi UX (User Experience) ala HTML statis super cepat.

Siap Migrasi?

Jangan biarkan user Anda menunggu loading spinner. Pelajari Astro lebih dalam sekarang.