Kaynak: hafiz.dev
Bir Inertia ile tam yığın Laravel uygulaması geliştirdiyseniz, yaşadığınız zorlukları bilirsiniz. Bir rota adını değiştirip, React bileşeninizi güncellemeyi unuttuğunuzda, form gönderiminizin neden 404 hata kodu aldığını çözmek için yirmi dakika harcayabilirsiniz. Ya da form isteği doğrulaması için yeni bir alan eklediğinizde, frontend hala eski veri yapısını göndermeye devam edebilir.
Laravel Wayfinder bu sorunları çözüyor. PHP kodunuzu okuyarak, backend’le senkronize kalan TypeScript üretiyor. Route’lar, form isteği türleri, model türleri, enum’lar—frontend’inizin backend hakkında bilmesi gereken her şey otomatik olarak üretiliyor ve türleniyor.
Öne çıkan bir güncelleme: Ocak 2026 itibarıyla, Wayfinder önemli bir beta sürümü ile geldi ve sadece rota üretiminin ötesine geçiyor. Önceki sürüm (Ziggy’nin yerini alan) yalnızca rotalarla ilgileniyordu. Bu yeni sürüm, form isteklerinden, Eloquent modellerine, PHP enum’larından, Inertia props’larına ve daha fazlasına kadar TypeScript üretiyor.
Şimdi, kurulumunu nasıl yapacağınızı ve özellikle form isteği entegrasyonunun neden kullanılmayı hak ettiğini göstereceğim.
Wayfinder ve Ziggy: Farklar Neler?
Wayfinder’dan önce çoğumuz rota üretimi için Ziggy kullanıyorduk. Ziggy’nin iyi yaptığı bir şey vardı: route('posts.show', { post: 1 }) ile JavaScript’te URL’i almanıza izin veriyordu; ama bunun dışında bir özelliği yoktu.
Wayfinder tamamen farklı bir yaklaşım sergiliyor. Sadece rota adlarını URL’lere eşleştirmek yerine, tüm Laravel kod tabanınızı analiz ediyor ve PHP yapılarınıza benzer TypeScript üretiyor.
| Özellik | Ziggy | Wayfinder |
|---|---|---|
| Rota URL’leri | ✓ | ✓ |
| HTTP yöntemi farkındalığı | ✗ | ✓ |
| Form istek türleri | ✗ | ✓ |
| Eloquent model türleri | ✗ | ✓ |
| PHP enum sabitleri | ✗ | ✓ |
| Inertia sayfa props’ları | ✗ | ✓ |
| Broadcast kanalları | ✗ | ✓ |
| Çevre değişkenleri | ✗ | ✓ |
Yalnızca rota üretimi bile Ziggy’den daha güçlü. Wayfinder, her kontrolör metodunun TypeScript işlevlerini oluşturur ve türleri ile birlikte getirir. Ancak asıl değer, özellikle form istek türlerindedir.
Laravel 12 itibarıyla, Wayfinder, resmi Başlangıç Kitlerinde Ziggy’nin yerini aldı. Yani, Inertia ile yeni bir Laravel projesine başlıyorsanız, stabil sürümü kullanıyorsunuz. Bu eğitim, genişletilmiş özelliklerle yeni beta sürümünü kapsamaktadır.
Kurulum ve Ayarlama
Öncelikle, beta sürümünü Composer ile kurun:
composer require laravel/wayfinder:dev-next
Üretilecekleri özelleştirmek için yapılandırma dosyasını yayınlayın:
php artisan vendor:publish --tag=wayfinder-config
Sonra, vite.config.js dosyasına Vite eklentisini ekleyin. Bu, PHP dosyalarınız değiştiğinde otomatik yeniden üretim sağlar:
import { wayfinder } from "@laravel/vite-plugin-wayfinder";
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.tsx'],
refresh: true,
}),
wayfinder(),
react(),
],
});
TypeScript dosyalarını üretin:
php artisan wayfinder:generate
Varsayılan olarak, Wayfinder her şeyi resources/js/wayfinder dizinine çıktılar. Eğer farklı bir konum isterseniz:
php artisan wayfinder:generate --path=resources/ts/api
İşte çoğu eğitimde atlanan bir nokta: Vite eklentisini yapılandırdığınızda, geliştirme sırasında generate komutunu manuel olarak çalıştırmanıza gerek kalmaz. Vite’in geliştirme sunucusu çalışırken, Wayfinder PHP dosyalarındaki değişiklikleri izler ve otomatik olarak yeniden üretir. Bir rotayı değiştirirseniz veya bir form isteğini güncellerseniz—TypeScript’niz birkaç saniye içinde güncellenir.
Herhangi bir yapı oluşturma sırasında yeniden üretildiği için wayfinder dizinini .gitignore‘unuza güvenle ekleyebilirsiniz.
Rota Üretim Temelleri
Tipik bir kontrolör ile başlayalım:
class PostController
{
public function index() { /* ... */ }
public function show(Post $post) { /* ... */ }
public function store(StorePostRequest $request) { /* ... */ }
public function update(UpdatePostRequest $request, Post $post) { /* ... */ }
public function destroy(Post $post) { /* ... */ }
}
Wayfinder, TypeScript modülünü oluşturur ve herhangi bir işlev gibi çağırabilirsiniz:
import { PostController } from "@/wayfinder/App/Http/Controllers/PostController";
// URL ve HTTP yöntemi döner
PostController.index();
// { url: '/posts', method: 'get' }
// Parametreli rotalar türlenmiştir
PostController.show({ post: 1 });
// { url: '/posts/1', method: 'get' }
PostController.update({ post: 42 });
// { url: '/posts/42', method: 'put' }
Sadece URL dizesine ihtiyacınız varsa? Her işlevin bir .url() yöntemi vardır:
PostController.show.url({ post: 42 });
// '/posts/42'
Sorgu parametreleri de çalışır:
PostController.index({ query: { page: 2, sort: "created_at" }});
// { url: '/posts?page=2&sort=created_at', method: 'get' }
Laravel’ın route() yardımcı fonksiyonu gibi adlandırılmış rotaları tercih ediyorsanız, Wayfinder bunları da oluşturur:
import posts from "@/wayfinder/routes/posts";
posts.index();
posts.show({ post: 1 });
TypeScript derleyicisi, parametre hatalarını yapı inşaat zamanında yakalar. PostController.show() işlevini post parametresini göndermeden çağırmaya çalıştığınızda, kodunuz çalışmadan önce bir hata alırsınız.
Inertia ile Form Yönetimi
İşte burada Wayfinder gerçekten faydalı hale geliyor.
HTML formları yalnızca GET ve POST yöntemlerini destekler. PUT, PATCH veya DELETE yöntemlerine ihtiyacınız olduğunda, Laravel yöntem sahteciliği kullanır, bu da aslında ne yapmak istediğinizi framework’e bildiren gizli bir _method alanıdır. Wayfinder, bununla birlikte .form değişkenini otomatik olarak yönetir:
PostController.update.form({ post: 1 });
// { action: '/posts/1?_method=PATCH', method: 'post' }
PostController.destroy.form({ post: 1 });
// { action: '/posts/1?_method=DELETE', method: 'post' }
Bunları doğrudan React’taki form elemanınıza yayabilirsiniz:
{...PostController.update.form({ post: post.id })}>
{/* fields */}
Ancak işte asıl güzel olanı: form isteği doğrulama kuralları, TypeScript türleri haline gelir.
Aşağıdaki Laravel form isteğini düşünün:
class StorePostRequest extends FormRequest
{
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string'],
'excerpt' => ['nullable', 'string'],
'tags' => ['nullable', 'array'],
'tags.*' => ['string'],
'meta' => ['nullable', 'array'],
'meta.description' => ['nullable', 'string'],
];
}
}
Wayfinder, bunu types.d.ts dosyasında üretir:
export namespace App.Http.Controllers.PostController.Store {
export type Request = {
title: string;
body: string;
excerpt?: string | null;
tags?: string[];
meta?: {
description?: string | null;
};
};
}
Nullable alanların nasıl ele alındığını (isteğe bağlı olarak ? ile işaretlenmiş), dizilerini ve hatta iç içe nesneleri nasıl yönettiğini gözlemleyin. tags.* kuralı string[] olur. meta.description kuralı ise iç içe bir nesne türüne dönüşür.
Artık bunu Inertia’nın useForm özelliği ile kullanabilirsiniz:
import { App } from "@/wayfinder/types";
import { useForm } from '@inertiajs/react';
const form = useForm<App.Http.Controllers.PostController.Store.Request>({
title: '',
body: '',
excerpt: null,
tags: [],
meta: {
description: null,
},
});
TypeScript artık hangi alanların geçerli olduğunu ve bunların türlerini tam olarak biliyor. Form isteğinde bir alan ekleyin, Wayfinder’ı yeniden üretin ve TypeScript, frontend formunuzu güncellemediğiniz takdirde hata verecektir.
İşte tam bir bileşen örneği:
import { App } from "@/wayfinder/types";
import { PostController } from "@/wayfinder/App/Http/Controllers/PostController";
import { useForm } from '@inertiajs/react';
export function CreatePost() {
const form = useForm<App.Http.Controllers.PostController.Store.Request>({
title: '',
body: '',
excerpt: null,
tags: [],
});
const submit = (e: React.FormEvent) => {
e.preventDefault();
form.post(PostController.store.url());
};
return (
<form onSubmit={submit}>
<input
name="title"
value={form.data.title}
onChange={e => form.setData('title', e.target.value)}
/>
{form.errors.title && <span>{form.errors.title}</span>}
<textarea
name="body"
value={form.data.body}
onChange={e => form.setData('body', e.target.value)}
/>
{/* TypeScript hatası eğer yanlış alan adı kullanırsanız */}
<button type="submit" disabled={form.processing}>Create Post</button>
</form>
);
}
Önemli bir nokta: doğrulama kurallarınız bir kez PHP’de tanımlanır. TypeScript türleri otomatik olarak üretilir. Artık backend’den uzaklaşan elle tanımlanmış tür tanımları yok. Yeni bir doğrulama kuralı eklediğinizde veya mevcut birini değiştirdiğinizde, frontend türleriniz bir sonraki inşaatta güncellenir.
Model Türleri
Wayfinder, Eloquent modellerinizi analiz eder ve onlar için TypeScript arayüzleri oluşturur. Örneğin:
class Post extends Model
{
protected $casts = [
'published_at' => 'datetime',
'is_featured' => 'boolean',
];
public function author(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
}
Wayfinder şunları üretir:
export namespace App.Models {
export type Post = {
id: number;
title: string;
body: string;
published_at: string | null;
is_featured: boolean;
author: App.Models.User;
tags: App.Models.Tag[];
created_at: string;
updated_at: string;
};
}
Tipleriyle birlikte dizi alanları, ilişkileri ve yapıların nasıl ele alındığını görebilirsiniz.
Bunları bileşenlerinizde kullanabilirsiniz:
import { App } from "@/wayfinder/types";
interface PostCardProps {
post: App.Models.Post;
}
export function PostCard({ post }: PostCardProps) {
return (
{post.title}
By {post.author.name}
{post.is_featured && Featured}
);
}
IDE’nizde tam otomatik tamamlama ve mevcut olmayan bir özelliğe erişirseniz, tür hataları alırsınız.
PHP Enum’ları
PHP 8.1 enum’ları doğrudan TypeScript’e çeviriliyor. Örneğin:
enum PostStatus: string
{
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
Wayfinder, hem tip (tip kontrolü için) hem de sabitler (çalışma zamanı için) üretir:
// types.d.ts dosyasında
export namespace App.Enums {
export type PostStatus = "draft" | "published" | "archived";
}
// App/Enums/PostStatus.ts dosyasında
export const Draft = "draft";
export const Published = "published";
export const Archived = "archived";
export const PostStatus = { Draft, Published, Archived } as const;
export default PostStatus;
Sabirleri kodunuzda kullanın:
import PostStatus from "@/wayfinder/App/Enums/PostStatus";
import { App } from "@/wayfinder/types";
interface Props {
post: App.Models.Post & { status: App.Enums.PostStatus };
}
export function PostStatusBadge({ post }: Props) {
if (post.status === PostStatus.Published) {
return Live;
}
if (post.status === PostStatus.Draft) {
return <span className="badge-yellow">Draft</span>;
}
return <span className="badge-gray">Archived</span>;
}
PHP’de yeni bir enum durumu ekleyin, yeniden üretin ve TypeScript, bununla başa çıkmamız gereken her yere haber verecektir.
Şu An Kullanmalı Mıyım?
Mevcut durumu net bir şekilde ifade etmek gerekirse, yeni Wayfinder, Joe Tannenbaum’un “büyük B beta” dediği bir aşamada. API, v1.0’dan önce değişebilir. Çok büyük kod tabanlarında performans optimizasyonuna ihtiyaç var. Karmaşık tür çıkarımlarıyla ilgili bazı kenar durumları henüz tamamen kapsanmıyor.
Yeni Inertia projeleri için: Evet, kullanın. Form isteği türleri bile, bazen saatlerce hata ayıklamanızı kurtarır. Break değişiklikleri yapılabilme olasılığı, verimlilik kazançlarından daha azdır ve API değişikliklerine uyum sağlamak oldukça basittir.
Mevcut projeler için: Durumunuzu değerlendirin. Orta ölçekli bir kod tabanınız varsa ve frontend/backend senkronizasyon sorunlarıyla baş etmeye çalışıyorsanız, denemeye değer. Eğer riske kapalı bir insansanız ya da büyük bir monolith varsa, belki beklemeniz daha iyi olur.
Şu an atladığım şeyler: Eğer, broadcast channel/event türleri veya çoklu depo senkronizasyonuna (gerçekten etkileyici) ilginiz varsa, o özellikler çalışıyor ama daha karmaşık kurulum gerektiriyor. Önce rotalara ve form isteğine odaklanın.
Takım aktif olarak GitHub’da geri bildirim topluyor. Karşılaştığınız sorunları bildirirseniz, hızlı bir yanıt veriyorlar ve paket hızla gelişiyor.
Burada Kapsanmayanlar
Bu yazı, günlük Inertia geliştirmesi için önemli olacağını düşündüğüm özellikler üzerinde yoğunlaştı. Wayfinder, daha fazla işlemin yanı sıra:
- Broadcast kanalları ve olaylar ile Laravel Echo WebSocket entegrasyonu için türlenmiş yüklerle
- Cross-repository senkronizasyon, ayrı frontend/backend repolarının senkronize edilmesi için GitHub Actions ile
- Inertia paylaşılan props’ların tipleri için
HandleInertiaRequestsmiddleware üzerinden - Vite çevresel değişken türleri için
import.meta.env
Bunların bazılarını gelecekteki yazılarda, API stabilize olduğunda ele alacağım.
Kaynaklar
SSS
Laravel Wayfinder nedir?
Laravel Wayfinder, PHP kodunuzdan TypeScript üreten resmi bir Laravel paketidir. Kontrolörlerinizi, rotalarınızı, form isteklerinizi, modellerinizi ve enum’larınızı analiz ederek, backend ile senkronize kalan tam türlenmiş TypeScript oluşturur.
Wayfinder ile Ziggy arasındaki fark nedir?
Ziggy yalnızca rota adlarından rota URL’leri oluşturur. Wayfinder, rota URL’lerini, HTTP yöntemlerini, form istek türlerini, model türlerini, PHP enum sabitlerini, Inertia sayfa props’larını ve daha fazlasını üretir. Wayfinder, Laravel 12 itibarıyla resmi Başlangıç Kitlerinde Ziggy’nin yerini almıştır.
Wayfinder Vue ve React ile çalışıyor mu?
Evet. Wayfinder, herhangi bir frontend ile çalışan çerçeve bağımsız TypeScript üretir. Inertia.js ile (hem Vue hem de React adaptörleri) için türlenmiş sayfa props’ları ve paylaşılan veriler içerir. Laravel Echo ile Vue veya React kullanıyorsanız, ayrıca türlenmiş olay işleyicileri de oluşturabilir.
Wayfinder prodüksiyon için hazır mı?
Yeni sürüm, kamu beta aşamasında. Önceki sürüm (sadece rota üretimi) stabil ve Laravel Başlangıç Kitleri ile birlikte gelir. Beta özellikleri için (form istekleri, modeller, enum’lar), API, v1.0’dan önce değişebilir, ancak işlevsel ve aktif olarak geliştirilmiştir. Yeni projeler için kullanırım; mevcut üretim uygulamaları için risk toleransınıza göre değerlendirin.
Kaynak: Orijinal Makale


