Yeniden Yazım Ne Olmadı
Yeniden Yazım Ne Olmadı
Modern bir frontend’e ihtiyacımız vardı. Blade + Bootstrap + jQuery yığını artık eski kalıyordu. Tasarım ekibi yeni bir UI/UX vizyonuna sahipti. Doğal eğilim ise: frontend’i React ile yeniden yazmaktı.
Ancak büyük projeler yenileme süreçlerinde sık sık başarısızlıkla sonuçlanır. Joel Spolsky bununla ilgili 2000 yılında yazıyordu. Fred Brooks’tan önceki yıllarda bunu açıkladı. Pattern her zaman aynıdır: Aylar boyunca Yeni Şey’i inşa edersiniz, eski şey sürekli yamanır, ikisi farklılaşır ve sonunda düzgün çalışan bir sistem yerine iki bozuk sisteminiz olur.
Bu yüzden yeniden yazmadık. Göç ettik. Sayfa sayfa. Özellik özellik. Ve her iki frontend’in birlikte var olabilmesi için bir mimari kurduk; geliştiriciler akıl sağlığını kaybetmeden.
İki Yol, Bir Kod Tabanı
İki Yol, Bir Kod Tabanı
Uygulama iki frontend mimarisini aynı anda çalıştırıyor:
| Path | Server Layer | UI Layer | Status |
|---|---|---|---|
| Legacy | Web controller’ları | Blade görünümleri | Sadece hata düzeltmeleri |
| SPA | API controller’ları | React + TypeScript | Tüm yeni özellikler |
Legacy yolu yaklaşık ~228 Blade görünümü ve ~59 web controller’ı barındırıyor. Çalışıyor. Kullanıcılar ona bağımlı. Kırılmazsa ona dokunmuyoruz.
SPA yolu hedef mimari. React 19, TypeScript 5, Tailwind CSS 4, /app adresinde bir catch-all route aracılığıyla mount edilir:
Route::get('/app/{any?}', [SpaController::class, 'index'])
->where('any', '.*')
->middleware(['auth', 'verified', 'onboarding', '2fa']);
SPA, başlangıç durumunu (kullanıcı, CSRF token) Blade üzerinden window.__INITIAL_STATE__ aracılığı ile alır; ardından React Router her şeyi istemci tarafında yönetir.
Ortam Kapatmaları
Ortam Kapatmaları
SPA, local, staging ve testing ortamlarına kapatılmıştır. Üretim yalnızca Legacy sayfalarını sunmaktadır (bir istisna ile).
// SpaController
public function index()
{
if (! in_array(app()->environment(), ['local', 'staging', 'testing'])) {
abort(404);
}
return view('spa.index');
}
Bu, SPA’yı üretimde hiçbir risk olmadan geliştirmemizi, test etmemizi ve yinelememizi sağlıyor. Staging, tam SPA deneyimini alıyor. Üretim, savaş alanında test edilmiş Blade görünümlerini alıyor.
Bir özellik SPA’da kararlı ve test edildikten sonra, iki seçeneğimiz vardır:
- SPA üretim için açık hale gelene kadar bekleyin.
- Mevcut interim wrapper deseni kullanarak hemen yayınlayın.
Geçici Wrapper Deseni
Geçici Wrapper Deseni
Bu, göç sürecini pratik hale getiren numara. Bir SPA sayfası üretime hazır ama SPA ortam kapatması henüz açılmamışsa, React bileşenini bir Blade çatısı içerisine yerleştiriyoruz.
İşleyiş şekli:
1. SPA bileşeni gerçek bilgi kaynağıdır.
// resources/js/spa/pages/Dashboard/Dashboard.tsx
export function Dashboard({ dashboardUrl = '/app/dashboard' }) {
const { data } = useDashboard(dashboardUrl);
return (
AppShell>
DashboardContent data={data} />
AppShell>
);
}
2. Ara geçici wrapper, onu eski URL geçersiz kılmalarıyla render eder.
// resources/js/dashboard/InterimDashboard.tsx
import { Dashboard } from '../spa/pages/Dashboard/Dashboard';
export function InterimDashboard() {
return Dashboard dashboardUrl="/dashboard" />;
}
3. Bağımsız bir mount dosyası, onu bir Blade çatısına besler.
// resources/js/dashboard/main.tsx
import { createRoot } from 'react-dom/client';
import { InterimDashboard } from './InterimDashboard';
createRoot(document.getElementById(dashboard-root)!).render(
InterimDashboard />
);
4. Bir Blade görünümü montaj noktasını sağlar.
{{-- dashboard/v2.blade.php --}}
@extends('layouts.app')
@section('content')
@viteReactRefresh
@vite('resources/js/dashboard/main.tsx')
@endsection
Temel içgörü: SPA bileşeni her zaman gerçek bilgi kaynağıdır. Ara geçici wrapper, yalnızca farklı URL özellikleri ile SPA bileşenini renderleyen ince bir plakadır. Hata düzeltmeleri SPA bileşenine gider ve her iki bağlamda da otomatik olarak uygulanır.
Bu şekilde altı özellik yayınladık:
| Özellik | SPA Bileşeni | Ara Wrapper | Blade Shell |
|---|---|---|---|
| Dashboard | Dashboard | InterimDashboard | v2.blade.php |
| Onboarding | OnboardingWizard | InterimOnboarding | onboarding.blade.php |
| Planner | PlannerWizard | InterimPlanner | index.blade.php |
| Guide | Guide | InterimGuide | index.blade.php |
| Marketplace | Marketplace | InterimMarketplace | index.blade.php |
| History | PlannerHistory | InterimPlannerHistory | history.blade.php |
Frontend Yenilemesi
Frontend Yenilemesi
Göç, aynı zamanda tüm frontend yığını modernize etmeyi de içeriyordu. Bu, dikkatli bir sırayla gerçekleşti:
1. Tailwind CSS 4 + Shadcn/ui
Bootstrap yerine Tailwind ile değiştirildi. Tutarlı React bileşenleri için Shadcn/ui eklendi. Bu temel katmandı.
2. SPA sayfaları taşındı
Tüm mevcut React sayfaları, Tailwind ve Shadcn/ui bileşenlerini kullanacak şekilde güncellendi.
3. jQuery’nin kaldırılması
Her $(document).ready() ve $.ajax() çağrısı yerini saf JS ile değiştirdi. jQuery bundle’dan çıkarıldı.
4. Blade şablonları göçtü
Tüm 228 Blade görünümü, Bootstrap sınıflarından Tailwind sınıflarına değiştirildi. Bu en büyük tek PR’di, ancak neredeyse tamamen CSS sınıf değişiklikleri; mantık değişikliği yoktu.
5. Livewire’dan React’a
Sahip olduğumuz birkaç Livewire bileşeni yeniden React’ta yapıldı.
6. Ölü kod kaldırma
Legacy frontend bağımlılıkları, kullanılmayan JS dosyaları ve Bootstrap kalıntıları temizlendi.
Her biri ayrı bir PR olarak, bağımsız şekilde test edilerek birkaç gün içinde ana dala birleştirildi. Uzun ömürlü dallar yok. Birleştirme çatışması yok. Test paketi her değişiklikten sonra hiçbir şeyin bozulmadığını doğruladı.
Özellik Flag’leri
Özellik Flag’leri
Yavaş yavaş yayımlanması veya A/B testleri gerektiren özellikler için özelllik flagleri/analitik servisi kullandık:
// Server-side feature gate
if ($this->analytics->checkGate($user, 'new_dashboard_layout')) {
return view();
}
return view();
Analitik servisi ayrıca olay izleme işlemlerini de yönetmektedir. Her anlamlı kullanıcı hareketi (sipariş oluşturma, bilet gönderme, dashboard görüntüleme) loglanır:
$this->analytics->logDashboardView($user, );
AnalyticsService, SDK’yi sarar ve ANALYTICS_ENABLED=false olduğunda no-op yapar; böylece testler ve yerel geliştirme etkilenmez.
Kapsam Kuralları
Kapsam Kuralları
Herkesin (insanların ve ajansların) aklını bulandırmamak için, net kapsam kuralları belirledik:
Legacy sadece bir alanda hata? Web controller’da ve Blade görünümünde düzeltin.
Göç edilen bir alanda hata? SPA React bileşeninde düzeltin. Bu otomatik olarak her iki bağlama da uygulanır.
Herhangi bir alanda yeni özellik? API uç noktasını ve SPA sayfasını oluşturun. Yeni Blade özellikleri eklemeyin.
Bir alanı göç ettirirken? Sırayı takip edin: Actions’a çıkar → API controller’ı oluştur → React sayfası oluştur → Ara geçici wrapper oluştur (gerekirse).
Bu kurallar CLAUDE.md harness dosyalarında belgelenmiştir (buna 7–8. gönderilerde geleceğiz). Ajans kuralları okur ve takip eder. Yeni kodun nereye gideceği hakkında belirsizlik yoktur.
Varlık Boru Hattı
Varlık Boru Hattı
Vite 6 hem SPA’yı hem de ara wrapper’ları yönetir:
// vite.config.ts
export default defineConfig({
plugins: [
laravel({
input: [
'resources/js/spa/main.tsx', // SPA girişi
'resources/js/dashboard/main.tsx', // Ara: Dashboard
'resources/js/onboarding/main.tsx', // Ara: Onboarding
'resources/js/planner/main.tsx', // Ara: Planner
// ...
],
}),
react(),
],
});
Her ara geçici wrapper kendi giriş noktasını alır. Vite, kullanılmayan kodu ağaç sarsması yapar. SPA kendi paketini alır. Blade sayfaları ihtiyacı olan belirli girişi @vite() aracılığıyla alır.
Çıkarımlar
Çıkarımlar
- Asla yeniden yazmayın. Göç edin. Sayfa sayfa, özellik özellik, her iki sistem paralel çalışacak şekilde.
- Yeni şeyi kapatın. SPA’nın üretime açılmasına izin vermeden önce, provedilmesi gereken aşama ortamında.
- Erken yayın için wrapper kullanın. Ara geçici desen, SPA sayfalarının eski çatılar içinde yayınlanmasına imkan tanır.
- SPA bileşeni her zaman gerçek bilgi kaynağıdır. Wrapper yalnızca borulama işlevini görür.
- Açık kapsam kuralları kodun nereye gideceğine dair kafa karışıklığını önler.
- Özellik flag’leri yavaşça yayma ve deneyleme için kullanılır.
Bu mimari, hiçbir zaman duraklamadığımız anlamına geliyor. Özellikleri bugün (ara wrapper’lar aracılığı ile) üretime gönderebiliriz; tam SPA’yı geliştirirken. Hiçbir baskı yok. Büyük bir patlama yok. Sadece düzenli bir ilerleme.
Kaynak: Orijinal Makale


