Kombinasi Laravel dan Inertia.js telah menjadi pilihan populer untuk membangun Single Page Application (SPA) yang modern tanpa kompleksitas API tradisional. Dengan Inertia, kamu bisa merasakan pengalaman SPA yang smooth sambil tetap mempertahankan routing dan controller Laravel yang familiar. Namun, seperti halnya teknologi lain, ada beberapa hal penting yang perlu diperhatikan agar pengembangan berjalan lancar.
Setelah menggunakan stack ini dalam berbagai project, aku menemukan bahwa developer sering menghadapi masalah yang sebenarnya bisa dihindari dengan pemahaman yang tepat. Mari kita bahas hal-hal krusial yang harus kamu perhatikan.
Setup dan Konfigurasi yang Tepat
Langkah pertama yang sering diabaikan adalah setup yang benar. Banyak developer yang terburu-buru langsung coding tanpa memastikan konfigurasi dasar sudah optimal.
Instalasi Server-Side Adapter
Pastikan kamu menginstal adapter Laravel dengan versi yang tepat:
composer require inertiajs/inertia-laravel:^2.0
Untuk project baru, gunakan selalu versi terbaru. Inertia v2.0 membawa banyak perbaikan performa dan fitur baru yang akan memudahkan development.
Middleware Registration yang Benar
Salah satu kesalahan umum adalah lupa mendaftarkan atau salah menempatkan middleware Inertia. Publish middleware terlebih dahulu:
php artisan inertia:middleware
Kemudian daftarkan di bootstrap/app.php
:
use App\Http\Middleware\HandleInertiaRequests;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
HandleInertiaRequests::class,
]);
})
Konfigurasi Frontend Dependencies
Jangan lupa install dependencies frontend yang sesuai dengan framework pilihan:
# Untuk Vue 3
npm install @inertiajs/vue3
npm install --save-dev @vitejs/plugin-vue
# Untuk React
npm install @inertiajs/react
npm install --save-dev @vitejs/plugin-react
Manajemen Data dan Props yang Efisien
Salah satu kekuatan Inertia adalah kemudahan passing data dari controller ke frontend. Namun, ada beberapa hal yang harus diperhatikan untuk performa optimal.
Hanya Kirim Data yang Diperlukan
Hindari mengirim model lengkap dengan semua atribut. Gunakan only()
atau select()
untuk membatasi data:
class UserController extends Controller
{
public function show(User $user)
{
return Inertia::render('User/Show', [
'user' => $user->only('id', 'name', 'email', 'created_at'),
]);
}
}
Manfaatkan Lazy Loading untuk Data Berat
Untuk data yang tidak immediately needed, gunakan closure untuk lazy evaluation:
return Inertia::render('Dashboard', [
'stats' => fn () => $this->getExpensiveStats(),
'recentUsers' => fn () => User::latest()->take(10)->get(),
]);
Deferred Props untuk Performance
Fitur deferred props sangat berguna untuk data yang bisa dimuat setelah initial render:
Route::get('/users', function () {
return Inertia::render('Users/Index', [
'users' => User::all(),
'roles' => Role::all(),
'permissions' => Inertia::defer(fn () => Permission::all()),
]);
});
Props yang di-defer akan dimuat secara terpisah, membuat initial page load lebih cepat.
Handling Forms dan Validation
Form handling dalam Inertia memiliki nuansa tersendiri yang perlu dipahami dengan baik.
Server-Side Validation yang Konsisten
Validasi harus dilakukan di server dengan pattern yang konsisten:
class UsersController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'name' => ['required', 'max:50'],
'email' => ['required', 'max:50', 'email', 'unique:users'],
]);
User::create($validated);
return to_route('users.index');
}
}
Redirect Handling yang Benar
Setelah POST/PUT/DELETE requests, selalu redirect ke route GET yang tepat. Jangan pernah return render langsung:
// ✅ Benar
public function store(Request $request)
{
// validation dan create logic
return to_route('users.index');
}
// ❌ Salah
public function store(Request $request)
{
// validation dan create logic
return Inertia::render('Users/Index', ['users' => User::all()]);
}
Error Handling dan Flash Messages
Manfaatkan Laravel’s session flash untuk error handling:
public function update(Request $request, User $user)
{
try {
$user->update($request->validated());
return to_route('users.show', $user)
->with('success', 'User updated successfully');
} catch (Exception $e) {
return back()
->with('error', 'Failed to update user');
}
}
Shared Data dan Global State
Pengelolaan data yang dibagikan across pages sangat penting untuk konsistensi aplikasi.
Shared Data via Middleware
Gunakan HandleInertiaRequests
middleware untuk data global:
class HandleInertiaRequests extends Middleware
{
public function share(Request $request)
{
return array_merge(parent::share($request), [
'appName' => config('app.name'),
'auth' => [
'user' => $request->user()
? $request->user()->only('id', 'name', 'email')
: null,
],
'flash' => [
'success' => session('success'),
'error' => session('error'),
],
]);
}
}
Authorization Data Sharing
Untuk aplikasi dengan authorization, share permission data:
'can' => [
'create_posts' => Auth::user()?->can('create', Post::class),
'manage_users' => Auth::user()?->can('viewAny', User::class),
],
Asset Versioning dan Caching
Asset versioning adalah crucial untuk production deployment yang smooth.
Automatic Asset Versioning
Biarkan Inertia handle asset versioning secara otomatis:
class HandleInertiaRequests extends Middleware
{
public function version(Request $request)
{
return parent::version($request);
}
}
Manual Versioning untuk Control yang Lebih
Jika perlu kontrol manual, kamu bisa set custom version:
use Inertia\Inertia;
// Di service provider
Inertia::version(fn () => md5_file(public_path('js/app.js')));
Testing Strategy yang Solid
Testing Inertia applications memerlukan approach yang sedikit berbeda.
Testing Inertia Responses
Gunakan AssertableInertia
untuk testing yang comprehensive:
use Inertia\Testing\AssertableInertia as Assert;
class UsersControllerTest extends TestCase
{
public function test_users_index()
{
$this->get('/users')
->assertInertia(fn (Assert $page) => $page
->component('Users/Index')
->has('users', 3)
->has('users.0', fn (Assert $page) => $page
->where('id', 1)
->where('name', 'John Doe')
->etc()
)
);
}
}
Testing Shared Data
Pastikan shared data tertest dengan baik:
public function test_auth_data_is_shared()
{
$user = User::factory()->create();
$this->actingAs($user)
->get('/dashboard')
->assertInertia(fn (Assert $page) => $page
->has('auth.user', fn (Assert $page) => $page
->where('id', $user->id)
->where('name', $user->name)
)
);
}
Common Pitfalls dan Cara Menghindarinya
Berdasarkan pengalaman, ada beberapa jebakan umum yang sering dialami developer.
Memory Leaks pada Data Besar
Hindari loading relasi yang besar tanpa pagination:
// ❌ Berbahaya untuk data besar
'posts' => $user->posts()->with('comments')->get(),
// ✅ Lebih aman dengan pagination
'posts' => $user->posts()->with('comments')->paginate(10),
N+1 Query Problems
Selalu gunakan eager loading untuk relasi:
// ❌ N+1 problem
'users' => User::all()->map(fn($user) => [
'name' => $user->name,
'posts_count' => $user->posts->count(),
]),
// ✅ Eager loading
'users' => User::withCount('posts')->get()->map(fn($user) => [
'name' => $user->name,
'posts_count' => $user->posts_count,
]),
Inconsistent URL Resolution
Pastikan URL resolution konsisten across application:
// Di HandleInertiaRequests middleware
public function urlResolver()
{
return function (Request $request) {
return $request->fullUrl();
};
}
Production Deployment Considerations
Untuk production, ada beberapa hal tambahan yang perlu diperhatikan.
Server-Side Rendering (SSR)
Jika perlu SEO optimal, setup SSR:
npm run build:ssr
composer dev:ssr
Error Handling untuk Production
Setup proper error handling di bootstrap/app.php
:
use Inertia\Inertia;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
if (! app()->environment(['local', 'testing']) &&
in_array($response->getStatusCode(), [500, 503, 404, 403])) {
return Inertia::render('ErrorPage', [
'status' => $response->getStatusCode()
])->toResponse($request)->setStatusCode($response->getStatusCode());
}
return $response;
});
})
Cache Strategy untuk Performance
Implementasikan caching yang tepat:
public function index()
{
$users = Cache::remember('users.all', 3600, function () {
return User::select('id', 'name', 'email')->get();
});
return Inertia::render('Users/Index', [
'users' => $users,
]);
}
Security Best Practices
Security tidak boleh diabaikan dalam Inertia applications.
Data Sanitization
Selalu sanitize data yang dikirim ke frontend:
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
// Jangan kirim sensitive data seperti password, tokens, dll
],
CSRF Protection
Pastikan CSRF protection aktif untuk semua form submissions:
// Middleware CSRF sudah include by default di web routes
// Pastikan meta tag ada di layout:
@csrf
Authorization Checks
Selalu lakukan authorization check di controller:
public function edit(User $user)
{
$this->authorize('update', $user);
return Inertia::render('Users/Edit', [
'user' => $user->only('id', 'name', 'email'),
]);
}
Laravel + Inertia adalah kombinasi yang powerful untuk modern web development. Dengan memperhatikan hal-hal di atas, kamu bisa membangun aplikasi yang tidak hanya functional tapi juga performant dan maintainable.
Yang terpenting adalah konsistensi dalam pattern dan best practices. Mulai dengan setup yang benar, kelola data dengan bijak, dan selalu prioritaskan security dan performance. Dengan foundation yang solid ini, development experience akan jauh lebih smooth dan enjoyable.
Happy coding dengan Laravel + Inertia! Semoga artikel ini membantu kamu menghindari common pitfalls dan membangun aplikasi yang awesome.