Pada aplikasi Laravel yang menggunakan Inertia.js, ada kebutuhan berulang untuk mengirim data yang sama ke banyak halaman. Contohnya adalah data user yang sedang login, nama aplikasi, atau notifikasi flash setelah proses create, update, dan delete. Jika setiap controller mengirim data itu secara manual, kode menjadi berulang, sulit dirawat, dan rawan inkonsistensi.
Di sinilah shared props berperan. Inertia menyediakan mekanisme untuk membagikan props global ke seluruh halaman melalui middleware, yang di Laravel umumnya diatur lewat HandleInertiaRequests. Pola ini sangat berguna, tetapi juga perlu digunakan dengan hati-hati. Jika semua data dibagikan secara global tanpa seleksi, performa dapat menurun dan risiko kebocoran data sensitif meningkat.
Artikel ini membahas cara kerja shared props di Laravel + Inertia.js, implementasi middleware yang rapi, pengiriman flash message success/error, cara mengakses props di Vue, serta praktik terbaik agar data global tetap aman dan efisien.
Mengapa Shared Props Dibutuhkan?
Dalam arsitektur Inertia, server merender respons berupa komponen halaman dan sekumpulan props. Props ini akan diterima oleh frontend, misalnya Vue. Secara default, setiap halaman menerima props yang dikirim dari controller atau route handler. Namun ada data yang hampir selalu dibutuhkan di banyak halaman, misalnya:
- Informasi user yang sedang login
- Nama aplikasi untuk navbar, title, atau footer
- Flash message dari session
- Preferensi UI sederhana seperti locale atau timezone
Tanpa shared props, Anda akan menulis hal serupa berulang kali di banyak controller. Dengan shared props, data tersebut cukup didefinisikan sekali di middleware, lalu tersedia di seluruh halaman Inertia.
Prinsip pentingnya: bagikan hanya data yang benar-benar sering dipakai secara global. Jangan menjadikan shared props sebagai tempat semua data aplikasi.
Peran Middleware HandleInertiaRequests
Laravel biasanya sudah menyediakan middleware HandleInertiaRequests saat Anda memasang stack Inertia. Middleware ini umumnya berada di:
app/Http/Middleware/HandleInertiaRequests.phpMiddleware ini mewarisi kelas dasar Inertia dan memiliki method share() yang digunakan untuk mendefinisikan data global. Method tersebut akan digabung dengan shared data bawaan dari parent class.
Contoh implementasi shared props
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
protected $rootView = 'app';
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'app' => [
'name' => config('app.name'),
],
'auth' => [
'user' => $request->user()
? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
]
: null,
],
'flash' => [
'success' => fn () => $request->session()->get('success'),
'error' => fn () => $request->session()->get('error'),
],
]);
}
}Struktur di atas cukup umum dan mudah dipakai di frontend:
app.nameuntuk konfigurasi global sederhanaauth.useruntuk data user loginflash.successdanflash.erroruntuk notifikasi
Mengapa beberapa nilai dibungkus closure?
Pada contoh di atas, flash message dibungkus dengan closure:
'success' => fn () => $request->session()->get('success')Pola ini berguna karena evaluasi nilainya dapat ditunda sampai benar-benar diperlukan oleh Inertia. Untuk data ringan efeknya mungkin kecil, tetapi untuk shared props yang bergantung pada proses lebih mahal, pendekatan lazy seperti ini membantu mengurangi overhead yang tidak perlu.
Shared Props untuk Auth User
Salah satu kebutuhan paling umum adalah menampilkan informasi user login pada layout, navbar, profile menu, atau halaman lain. Shared props membuat data ini tersedia secara konsisten.
Batasi field yang dibagikan
Kesalahan yang sering terjadi adalah langsung mengirim seluruh model user ke frontend:
'auth' => [
'user' => $request->user(),
]Walaupun terlihat praktis, ini berisiko. Model user bisa saja memiliki atribut yang tidak seharusnya tersebar ke semua halaman, misalnya:
- role internal yang belum perlu ditampilkan
- timestamp yang tidak relevan
- flag atau metadata sensitif
- relasi yang ikut termuat secara tidak sengaja
Praktik yang lebih aman adalah membuat payload eksplisit hanya dengan field yang memang dibutuhkan UI. Misalnya:
'auth' => [
'user' => $request->user()
? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
]
: null,
]Jika aplikasi Anda memerlukan role atau permission di frontend, tetap pilih field minimal yang relevan. Jangan mengirim semua relasi permission jika yang dibutuhkan hanya boolean seperti can.manageUsers.
Kapan memakai shared auth user, kapan tidak?
Shared auth user cocok jika informasi itu dipakai hampir di semua halaman, misalnya untuk header atau menu. Namun jika ada halaman tertentu yang memerlukan profil lengkap, statistik akun, avatar, dan relasi tambahan, kirim data tersebut secara spesifik dari controller halaman itu. Dengan begitu payload global tetap kecil.
Konfigurasi Global Seperti App Name
Data konfigurasi sederhana juga cocok ditempatkan di shared props. Contoh paling umum adalah nama aplikasi:
'app' => [
'name' => config('app.name'),
]Keuntungannya adalah frontend tidak perlu hardcode nama aplikasi di banyak komponen. Jika nama aplikasi berubah, Anda cukup memperbarui konfigurasi Laravel. Pola ini juga berguna untuk:
- environment label non-sensitif, misalnya “Staging”
- locale aktif
- timezone default untuk tampilan
Namun hindari membagikan konfigurasi internal yang tidak relevan bagi UI, apalagi yang bisa membuka detail infrastruktur atau keamanan.
Flash Message Success dan Error
Flash message adalah data singkat yang disimpan di session dan biasanya hanya hidup untuk request berikutnya. Dalam aplikasi Inertia, flash message umum dipakai setelah redirect, misalnya setelah berhasil menyimpan data.
Mengirim flash dari controller
Contoh setelah berhasil membuat data:
public function store(Request $request)
{
$validated = $request->validate([
'title' => ['required', 'string', 'max:255'],
]);
// Simpan data...
return redirect()
->route('posts.index')
->with('success', 'Post berhasil dibuat.');
}Contoh saat ingin memberi pesan error umum:
public function destroy(Post $post)
{
if ($post->is_locked) {
return redirect()
->route('posts.index')
->with('error', 'Post yang terkunci tidak bisa dihapus.');
}
$post->delete();
return redirect()
->route('posts.index')
->with('success', 'Post berhasil dihapus.');
}Karena flash message sudah dibagikan lewat middleware, frontend tinggal membacanya dari props global.
Mengakses flash message di Vue
Pada Vue dengan Inertia, Anda bisa memakai usePage() untuk mengakses props:
<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'
const page = usePage()
const appName = computed(() => page.props.app.name)
const authUser = computed(() => page.props.auth.user)
const flashSuccess = computed(() => page.props.flash.success)
const flashError = computed(() => page.props.flash.error)
</script>
<template>
<div>
<header>
<h2>{{ appName }}</h2>
<p v-if="authUser">Login sebagai {{ authUser.name }}</p>
</header>
<div v-if="flashSuccess" class="alert alert-success">
{{ flashSuccess }}
</div>
<div v-if="flashError" class="alert alert-danger">
{{ flashError }}
</div>
</div>
</template>Biasanya flash message ditampilkan di layout utama agar otomatis muncul di seluruh halaman setelah redirect. Ini lebih efisien dibanding menulis komponen notifikasi di setiap page component.
Data yang Sebaiknya Tidak Dibagikan Secara Global
Ini bagian yang paling penting dari sisi performa dan keamanan. Shared props akan ikut tersedia di banyak atau semua halaman Inertia. Artinya, setiap data yang Anda tempatkan di sana perlu diperlakukan sebagai data global sungguhan.
Jangan bagikan data besar
Hindari menaruh data berikut dalam shared props:
- Daftar panjang kategori, produk, atau user
- Hasil query dashboard yang kompleks
- Relasi model yang besar
- Data statistik yang hanya relevan di satu halaman
Semakin besar props global, semakin berat payload tiap respons Inertia. Ini berdampak pada waktu transfer, parsing di browser, dan kompleksitas debugging.
Jangan bagikan data sensitif
Hindari memasukkan hal-hal berikut ke shared props:
- token API
- secret key atau informasi environment sensitif
- atribut internal user yang tidak perlu
- permission mentah yang membuka struktur otorisasi internal tanpa alasan
- data tenant atau organisasi yang tidak relevan di semua halaman
Perlu diingat, data yang dikirim ke frontend harus dianggap dapat dilihat oleh pengguna melalui DevTools. Walaupun tidak ditampilkan di UI, data tetap ada di payload respons.
Bagikan turunan data, bukan sumber mentahnya
Jika frontend hanya butuh informasi sederhana, kirim hasil olahan yang minimal. Contoh, daripada mengirim seluruh koleksi permissions, lebih baik kirim boolean yang jelas:
'auth' => [
'can' => [
'manage_users' => $request->user()?->can('manage users') ?? false,
],
]Pendekatan ini lebih hemat payload dan lebih aman karena frontend hanya menerima informasi yang diperlukan untuk rendering UI.
Tips Struktur dan Praktik Terbaik
Gunakan namespace props yang konsisten
Kelompokkan shared props secara terstruktur, misalnya:
app.*untuk konfigurasi aplikasiauth.*untuk user dan otorisasi sederhanaflash.*untuk notifikasi session
Struktur ini memudahkan tim memahami asal dan tujuan data.
Jangan campur kebutuhan layout dan kebutuhan halaman
Jika data dipakai hanya di satu halaman, kirim dari controller halaman itu. Shared props sebaiknya diisi hanya oleh data yang memang dipakai lintas halaman atau lintas layout.
Waspadai query tambahan di middleware
Method share() berjalan pada request Inertia. Jika Anda menambahkan query database berat di sana, biaya itu akan muncul berulang di banyak halaman. Jika memang perlu, pastikan query minimal, terindeks dengan baik, dan benar-benar dibutuhkan secara global.
Audit payload saat debugging
Jika halaman terasa lambat atau props terlalu besar, cek respons Inertia di browser DevTools. Perhatikan apakah ada data global yang terlalu besar, duplikatif, atau sensitif. Ini sering menjadi sumber masalah yang tidak terlihat dari sisi backend saja.
Pertimbangkan transformasi melalui resource atau DTO
Untuk aplikasi yang lebih besar, Anda dapat memisahkan transformasi data user ke class resource atau DTO agar bentuk data frontend lebih konsisten dan tidak bergantung langsung pada model Eloquent.
Kesalahan Umum yang Sering Terjadi
- Mengirim seluruh object user tanpa filter field.
- Menaruh query berat di shared props sehingga semua halaman ikut lambat.
- Menggunakan shared props untuk data halaman spesifik yang seharusnya dikirim lokal dari controller.
- Melupakan null handling ketika user belum login.
- Menyimpan flash message di tempat yang salah sehingga notifikasi tidak muncul setelah redirect.
Jika flash message tidak tampil, periksa tiga hal: apakah controller benar-benar memakai with('success', ...) atau with('error', ...), apakah middleware share() membaca session dengan key yang benar, dan apakah komponen Vue mengakses path props yang sesuai.
Penutup
Shared props di Inertia.js Laravel adalah pola penting untuk membagikan data global dengan rapi dan konsisten. Middleware HandleInertiaRequests menjadi tempat yang tepat untuk menyimpan data seperti nama aplikasi, user login, dan flash message success/error. Dengan pendekatan ini, layout dan page component menjadi lebih sederhana karena tidak perlu terus-menerus menerima data global dari setiap controller.
Meski demikian, shared props harus digunakan secara disiplin. Bagikan hanya data yang benar-benar bersifat global, batasi field yang dikirim, hindari query berat, dan jangan pernah mengirim data sensitif hanya demi kemudahan akses di frontend. Jika aturan ini dijaga, integrasi Laravel dan Inertia akan tetap efisien, aman, dan mudah dipelihara seiring aplikasi bertambah besar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!