Arsitektur Laravel + Inertia + React

Arsitektur Laravel + Inertia.js + React

Lesson Overview

Estimasi Waktu:
- Pemula: 25-35 menit
- Intermediate: 15-20 menit
- Advanced: 10 menit

Tipe Lesson: TEORI - Memahami konsep sebelum praktik
Output: Pemahaman tentang bagaimana Laravel, Inertia, dan React bekerja bersama

Sebelum mulai coding, penting untuk memahami bagaimana ketiga teknologi ini bekerja bersama. Kombinasi Laravel + Inertia.js + React memberikan pengalaman development yang unik - seperti membangun SPA modern tapi dengan kesederhanaan aplikasi monolith tradisional.

Bayangkan Anda sedang membangun sebuah restoran modern. Laravel adalah dapur tempat semua makanan (data) dimasak dan disiapkan. React adalah ruang makan tempat tamu (user) menikmati makanan dalam suasana yang nyaman. Inertia.js adalah pelayan yang mengantar makanan dari dapur ke meja tamu dengan efisien.

Tanpa pelayan (Inertia), Anda harus membuat sistem antar sendiri - seperti membuat REST API dimana dapur dan ruang makan berkomunikasi melalui nomor pesanan. Dengan pelayan (Inertia), komunikasi menjadi langsung dan natural - dapur tahu persis apa yang dimau tamu, dan tamu mendapat makanan tepat seperti yang dipesan.

Di lesson ini, kita akan mempelajari arsitektur ini secara mendalam agar Anda memiliki mental model yang jelas sebelum mulai menulis kode. Pemahaman arsitektur akan membantu Anda debugging lebih cepat dan membuat keputusan teknis yang tepat.

Yang Akan Dipelajari di Lesson Ini:

1. Apa itu Inertia.js - Mengapa kita pakai dan bagaimana cara kerjanya
2. Perbandingan 3 Arsitektur - MPA vs API+SPA vs Inertia
3. Alur Data - Bagaimana data mengalir dari Laravel ke React
4. Preview Kode - Contoh Controller dan React (belum perlu dibuat)
5. Kapan Pakai/Tidak Pakai - Batasan dan use case yang tepat
Mengapa Perlu Memahami Arsitektur?

Memahami arsitektur sebelum coding akan:
- Hemat waktu debugging - Tahu di mana letak masalah (Backend/Frontend/Bridge)
- Kode lebih terstruktur - Tahu file apa taruh di mana
- Mudah maintenance - Paham flow data dari database ke UI

Contoh Penggunaan:
1. Saat error "data tidak muncul" - cek Controller (Laravel) atau Component (React)?
2. Saat bikin fitur baru - butuh API atau cukup Inertia render?
3. Saat optimize performa - bottleneck di query (Laravel) atau render (React)?
Apa itu Inertia.js?

Bayangkan Anda punya 2 orang yang tidak bisa bicara langsung:
- Laravel (backend) - berbicara bahasa PHP
- React (frontend) - berbicara bahasa JavaScript

Inertia.js adalah penerjemah di antara mereka!

Tanpa Inertia: Anda harus buat API (REST/GraphQL) sebagai "bahasa perantara"
Dengan Inertia: Laravel langsung kirim data ke React, tanpa API!

Filosofi Inertia: "Build single-page apps, without building an API."

Perbandingan 3 Arsitektur

Ada tiga cara umum membangun aplikasi web modern, masing-masing dengan kelebihan dan kekurangannya. Memahami perbedaan ini akan membantu Anda memilih arsitektur yang tepat untuk setiap project.

Traditional MPA (Multi-Page Application) adalah cara klasik dimana setiap navigasi memuat halaman baru dari server - seperti buku yang harus membuka halaman baru setiap kali baca bab berikutnya. API + SPA adalah arsitektur modern dimana frontend dan backend terpisah total - seperti restoran dengan dapur di gedung berbeda. Inertia menggabungkan keduanya - satu gedung tapi dengan pengalaman restoran modern.

Tabel berikut membandingkan ketiga arsitektur dari berbagai aspek. Perhatikan bagaimana Inertia mengambil yang terbaik dari kedua dunia - routing server-side yang sederhana seperti MPA, tapi dengan pengalaman SPA tanpa page reload:

Aspek Traditional MPA API + SPA Inertia.js
Codebase 1 (Laravel + Blade) 2 (API + Frontend) 1 (Laravel + React)
Routing Server-side Dual (BE + FE) Server-side
Authentication Session Token (JWT) Session (aman)
Page Reload Full reload SPA (no reload) SPA (no reload)
Deployment 1 server 2+ servers 1 server

Bagaimana Inertia Bekerja?

Untuk memahami Inertia, kita perlu membedakan dua skenario: kunjungan pertama (initial page load) dan navigasi berikutnya (subsequent navigation). Perbedaan cara penanganan kedua skenario inilah yang membuat Inertia unik dan performant.

Bayangkan seperti menonton film di bioskop. Saat pertama kali masuk (initial load), Anda perlu beli tiket, popcorn, cari kursi, tunggu iklan selesai - prosesnya lengkap. Tapi kalau mau nonton film kedua (subsequent navigation), Anda sudah di dalam bioskop - cukup pindah studio saja tanpa perlu keluar dan masuk lagi.

Berikut adalah visualisasi step-by-step bagaimana Inertia memproses request di kedua skenario:

1. Initial Page Load (Kunjungan Pertama)

1
Browser request GET /dashboard
2
Laravel jalankan DashboardController@index
3
Inertia render: Inertia::render('Dashboard', $props)
4
Response: Full HTML + React Bundle + JSON Props
5
React hydrate component dengan props dari Laravel

2. Subsequent Navigation (Navigasi Berikutnya)

1
User klik <Link href="/employees">
2
Inertia kirim XHR dengan header X-Inertia: true
3
Laravel return JSON: {component, props, url}
4
Inertia swap React component - URL berubah, tanpa page reload!
Perbedaan Penting:

- Kunjungan pertama: Server kirim full HTML (seperti MPA biasa)
- Navigasi berikutnya: Hanya kirim JSON data (seperti SPA)

Ini yang membuat Inertia cepat dan SEO-friendly!
Analogi Sederhana - Restoran:

Bayangkan Anda ke restoran untuk pertama kali:

Kunjungan Pertama Pelayan bawa menu lengkap + piring + sendok + garpu + tisu (Full HTML + React Bundle)
Pesanan Berikutnya Pelayan hanya bawa makanan saja - piring dan sendok sudah ada di meja (JSON data saja)

Inilah mengapa navigasi kedua dan seterusnya terasa lebih cepat - browser sudah punya "peralatan makan" (React bundle), tinggal terima "makanan" (data) saja!

Contoh Kode (Preview)

Catatan: Kode di bawah ini adalah preview untuk memahami konsep. File-file ini akan dibuat di Section 6 (Employee Management).

Preview: Controller Laravel dengan Inertia

Dalam arsitektur Laravel + Inertia + React, Controller berperan sebagai penghubung antara database dan frontend. Berbeda dengan API tradisional yang mengembalikan JSON, Controller dengan Inertia mengembalikan response khusus yang berisi nama component React dan data (props) yang akan dikirim ke component tersebut.

Berikut adalah contoh bagaimana Controller Laravel mengirim data ke React component menggunakan Inertia::render(). Method ini menerima dua parameter: nama component React (tanpa ekstensi .tsx) dan array data yang akan menjadi props di React.

Lokasi File: app/Http/Controllers/EmployeeController.php
Aksi: [REFERENSI - TIDAK PERLU DIBUAT]
Fungsi file ini: Controller untuk mengelola CRUD Employee. Menerima HTTP request, mengambil data dari Model dengan Eloquent, dan mengirim data ke React page via Inertia::render().
Relasi dengan file lain: Dipanggil oleh Routes -> Ambil data dari Model Employee -> Kirim ke React component resources/js/Pages/Employees/Index.tsx via Inertia.
<?php

namespace App\Http\Controllers;

use App\Models\Employee;
use Inertia\Inertia;

class EmployeeController extends Controller
{
    /**
     * Menampilkan daftar karyawan dengan pagination
     * 
     * Alur:
     * 1. Query Employee dengan relasi department dan position
     * 2. Paginate hasil query (10 per halaman)
     * 3. Kirim ke React via Inertia::render()
     */
    public function index()
    {
        // ========== QUERY DATA ==========
        // Eager load relasi untuk menghindari N+1 problem
        $employees = Employee::with(['department', 'position'])
            ->paginate(10);
        
        // ========== KIRIM KE REACT ==========
        // Props ini akan tersedia di React component
        return Inertia::render('Employees/Index', [
            'employees' => $employees,  // Data karyawan dengan pagination
            'filters' => request()->only(['search', 'department']),
        ]);
    }
}

Kode di atas menunjukkan pola dasar Controller dengan Inertia. Pertama, kita menggunakan Employee::with(['department', 'position']) untuk eager loading relasi - ini mencegah N+1 query problem yang bisa memperlambat aplikasi. Kedua, paginate(10) membagi hasil query menjadi halaman-halaman berisi 10 data.

Yang membuat Inertia unik adalah method Inertia::render(). Parameter pertama 'Employees/Index' menunjuk ke file resources/js/Pages/Employees/Index.tsx. Parameter kedua adalah array associative yang akan menjadi props di React component. Dengan cara ini, data dari Laravel langsung tersedia di React tanpa perlu membuat API terpisah.

Preview: React Page Menerima Props

Di sisi React, kita menerima data yang dikirim Controller sebagai props. Dengan TypeScript, kita mendefinisikan interface untuk memastikan type safety - artinya TypeScript akan memberikan error di development jika kita mengakses property yang tidak ada atau dengan type yang salah.

Inertia.js secara otomatis meng-inject props dari Controller ke component React. Kita tidak perlu melakukan fetch atau axios call - data sudah tersedia saat component di-render.

Lokasi File: resources/js/Pages/Employees/Index.tsx
Aksi: [REFERENSI - TIDAK PERLU DIBUAT]
Fungsi file ini: React page component untuk menampilkan daftar karyawan. Menerima props dari Controller dan me-render UI dengan data tersebut.
Relasi dengan file lain: Menerima data dari EmployeeController@index via Inertia props. Menggunakan AuthenticatedLayout sebagai wrapper layout.
import { Head } from '@inertiajs/react';

/**
 * Interface untuk type Employee
 * Mendefinisikan struktur data karyawan dari backend
 */
interface Employee {
    id: number;
    full_name: string;
    department: { name: string };
}

/**
 * Interface untuk Props component
 * Harus sesuai dengan data yang dikirim dari Controller
 */
interface Props {
    employees: {
        data: Employee[];  // Array karyawan dari paginate()
    };
    filters: {
        search?: string;  // Filter search dari URL query
    };
}

/**
 * Page Component: Employee Index
 * Menampilkan daftar karyawan dalam format list
 * 
 * Props dari Controller langsung tersedia sebagai parameter!
 */
export default function Index({ employees, filters }: Props) {
    return (
        <>
            {/* Head untuk set title halaman */}
            <Head title="Employees" />
            
            {/* Container utama */}
            <div className="p-6">
                {/* Loop data karyawan */}
                {employees.data.map(emp => (
                    <div key={emp.id}>
                        {emp.full_name} - {emp.department.name}
                    </div>
                ))}
            </div>
        </>
    );
}
Apa itu Interface di TypeScript?

Jika Anda belum familiar dengan TypeScript, interface adalah cara mendefinisikan "bentuk" data. Bayangkan seperti formulir kosong yang menentukan field apa saja yang harus diisi:

Tanpa Interface (JavaScript biasa) Dengan Interface (TypeScript)
const emp = { nama: "Budi" }
console.log(emp.name) // undefined, typo!
Error baru ketahuan saat runtime
interface Employee { name: string }
const emp: Employee = { nama: "Budi" }
Error langsung muncul di IDE!

Jangan khawatir jika belum paham sepenuhnya - kita akan belajar TypeScript secara bertahap di lesson-lesson berikutnya!

Pada kode di atas, perhatikan bagaimana kita mendefinisikan interface Employee dan Props. Interface ini berfungsi sebagai "kontrak" antara backend dan frontend - jika Controller mengirim data dengan struktur berbeda, TypeScript akan memberikan warning di IDE. Ini sangat membantu mencegah bug runtime.

Function component Index menerima { employees, filters } sebagai destructured props. Data ini langsung dari Controller tanpa perlu API call. Component Head dari Inertia digunakan untuk mengatur title halaman secara dinamis. Kemudian kita me-loop employees.data (perhatikan: data pagination Laravel ada di property data) untuk menampilkan setiap karyawan.


Shared Data (Global Props)

Selain props per-halaman, Inertia juga menyediakan mekanisme "shared data" - data yang tersedia di SEMUA halaman React. Ini sangat berguna untuk data yang sering diakses seperti informasi user yang login, flash messages, atau konfigurasi aplikasi.

Shared data dikonfigurasi di middleware HandleInertiaRequests. Di sini kita bisa menambahkan data apapun yang akan tersedia di semua component React melalui usePage() hook atau $page props.

Lokasi File: app/Http/Middleware/HandleInertiaRequests.php
Aksi: [REFERENSI - TIDAK PERLU DIBUAT]
Fungsi file ini: Middleware untuk mendefinisikan shared data yang tersedia di semua halaman React. Berisi konfigurasi root template dan data global seperti auth user dan flash messages.
Relasi dengan file lain: Dijalankan otomatis oleh Laravel middleware stack. Semua React pages bisa mengakses data yang di-share melalui usePage().props.
<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    public function share(Request $request): array
    {
        return [
            ...parent::share($request),
            
            // Data ini tersedia di SEMUA React pages
            'auth' => [
                'user' => $request->user(),
            ],
            'flash' => [
                'success' => fn () => $request->session()->get('success'),
                'error' => fn () => $request->session()->get('error'),
            ],
        ];
    }
}

Kode di atas menunjukkan method share() yang mengembalikan array data yang akan tersedia di semua halaman. Key auth berisi informasi user yang sedang login - ini sangat berguna untuk menampilkan nama user di navbar atau mengecek permission. Key flash berisi pesan success/error yang akan ditampilkan sebagai notifikasi toast setelah melakukan aksi.

Perhatikan penggunaan closure fn () => untuk flash messages. Ini adalah optimasi - Inertia hanya akan memanggil closure saat data benar-benar dibutuhkan. Jika halaman tidak menggunakan flash data, closure tidak akan dieksekusi, menghemat resources.


Keuntungan Inertia untuk HRIS

Untuk aplikasi internal seperti HRIS, Inertia memberikan banyak keuntungan dibandingkan arsitektur lain. Berikut adalah beberapa keuntungan utama yang akan Anda rasakan selama development dan maintenance aplikasi.

Bayangkan seperti memilih kendaraan untuk perjalanan. Untuk perjalanan dalam kota (aplikasi internal), motor atau mobil lebih efisien daripada pesawat (microservices). Inertia adalah kendaraan yang tepat untuk aplikasi enterprise monolith yang tidak membutuhkan akses dari mobile app atau third-party.

Keuntungan-keuntungan ini menjadi sangat terasa saat tim Anda kecil atau saat Anda bekerja solo - tidak perlu maintain dua codebase atau setup infrastructure kompleks:

Satu Codebase
Tidak perlu maintain 2 repo terpisah
Session Auth
Lebih aman untuk aplikasi internal
Laravel Validation
Error otomatis di-share ke frontend
Simple Deployment
Cukup 1 server untuk semua

Kapan TIDAK Menggunakan Inertia?

Meskipun Inertia sangat powerful, ada situasi di mana arsitektur lain lebih cocok. Penting untuk memahami batasan ini agar tidak salah pilih teknologi.

Jangan Gunakan Inertia Jika:

Butuh Mobile App Jika Anda berencana membuat aplikasi iOS/Android yang mengakses data yang sama, Anda tetap perlu membuat REST API terpisah. Inertia hanya untuk web.
Tim Terpisah Jika tim backend dan frontend bekerja di repo berbeda dengan deployment terpisah, API + SPA lebih cocok karena memberikan kontrak yang jelas (OpenAPI/Swagger).
Public API Jika aplikasi Anda perlu diakses oleh third-party (integrasi dengan sistem lain), Anda perlu REST/GraphQL API yang bisa diakses dari luar.
Microservices Jika arsitektur Anda menggunakan banyak service terpisah, Inertia kurang cocok karena dirancang untuk monolith.
Inertia COCOK untuk:

- Aplikasi Internal - HRIS, CRM, ERP, Admin Panel
- Tim Full-stack - Satu tim handle backend dan frontend
- Startup/MVP - Butuh development cepat dengan satu codebase
- Aplikasi Web-only - Tidak ada rencana mobile app dalam waktu dekat

HRIS yang kita bangun di kursus ini adalah contoh sempurna use case Inertia!

Untuk referensi lebih lanjut, berikut dokumentasi resmi yang bisa Anda bookmark:


Checkpoint - Review Pemahaman

Sebelum melanjutkan ke lesson berikutnya, pastikan Anda sudah memahami konsep-konsep dasar arsitektur ini. Coba jawab pertanyaan berikut:

Langkah Review Pemahaman:

1. Fungsi Inertia.js:
Apa fungsi utama Inertia.js? Jelaskan dalam satu kalimat menggunakan analogi.

2. Perbedaan Load Type:
Apa perbedaan antara Initial Page Load dan Subsequent Navigation? Apa yang dikirim server di masing-masing?

3. Data Flow:
Bagaimana data dari Controller Laravel sampai ke React component? Method apa yang digunakan?

4. Shared Data:
Apa itu shared data? Di file mana konfigurasinya dan bagaimana React mengaksesnya?

5. Keuntungan Inertia:
Sebutkan minimal 3 keuntungan menggunakan Inertia untuk aplikasi internal seperti HRIS.

6. Batasan Inertia:
Kapan sebaiknya TIDAK menggunakan Inertia? Sebutkan minimal 2 situasi dan alasannya.
Jawaban Review:

1. Inertia.js adalah "penerjemah/pelayan" yang menghubungkan Laravel (dapur) dengan React (ruang makan) tanpa perlu membuat API terpisah - seperti pelayan yang mengantar makanan langsung dari dapur ke meja.

2. Initial Load: Server kirim full HTML + React bundle + JSON props (prosesnya lengkap seperti baru masuk bioskop). Subsequent Navigation: Server hanya kirim JSON data (cukup pindah studio karena sudah di dalam bioskop).

3. Data dikirim melalui Inertia::render('NamaComponent', ['key' => $data]). Data tersebut otomatis menjadi props di React component tanpa perlu fetch atau axios call.

4. Shared data adalah data global yang tersedia di SEMUA halaman React. Dikonfigurasi di HandleInertiaRequests.php method share(). React mengaksesnya via usePage().props.

5. Keuntungan Inertia: (a) Satu codebase - tidak perlu maintain 2 repo, (b) Session auth yang lebih aman untuk aplikasi internal, (c) Simple deployment - cukup 1 server, (d) Validasi Laravel otomatis tersedia di frontend.

6. Jangan pakai Inertia jika: (a) Butuh mobile app - karena tetap perlu API terpisah untuk iOS/Android, (b) Tim backend/frontend terpisah - lebih baik API + SPA dengan kontrak OpenAPI, (c) Butuh public API untuk third-party integration.

Ringkasan

Yang Sudah Dipelajari:

1. Inertia.js - "Penerjemah" antara Laravel dan React
2. Perbandingan Arsitektur - MPA vs API+SPA vs Inertia
3. Cara Kerja - Initial load (HTML) vs Navigation (JSON)
4. Controller ke React - Data langsung via props
5. Shared Data - Global props untuk semua pages
6. Keuntungan - 1 codebase, session auth, simple deployment
7. Batasan - Kapan tidak cocok menggunakan Inertia
Poin Penting untuk Diingat:

- Inertia bukan pengganti API - gunakan untuk aplikasi monolith
- Jika butuh mobile app, tetap perlu API terpisah
- Cocok untuk aplikasi internal seperti HRIS, CRM, ERP
- TypeScript interface membantu mencegah bug dengan type checking
Lesson Berikutnya: Instalasi Laravel + Breeze

Di lesson 3, kita akan mulai hands-on dengan:

- Install Laravel 12 fresh project
- Install Breeze dengan stack Inertia + React + TypeScript
- Konfigurasi database MySQL
- Jalankan migration dan test login

Pastikan software dari checklist Lesson 1 sudah terinstall sebelum melanjutkan!