100 bileşenlik bir React uygulamasında npm start yazıyorsunuz. Terminal satırlar fışkırıyor, tarayıcı bir süre boş bekliyor. On beş saniye, yirmi saniye, zaman zaman otuz. Proje büyüdükçe bu süre uzuyor; günde onlarca kez server yeniden başlatılıyorsa bekleme saatlere dönüşüyor.

Create React App (CRA), bu deneyimin somut adıdır. Webpack tabanlı yapısı dev modunda tüm proje grafiğini baştan çıkarmak zorunda kaldığı için başlangıç süresi doğrudan dosya sayısıyla orantılı artar. Vite ise sorunu kökünden farklı çözüyor: ES modüllerini tarayıcıya doğrudan gönderiyor, yalnızca talep edilen dosyayı derleme anında işliyor.

Dev server başlama süresi, HMR (Hot Module Replacement) hızı ve production build farkları pratikte neye benziyor; geçiş sürecinde hangi engeller öne çıkıyor - bunları gerçek geliştirme senaryoları üzerinden ele alıyoruz.

Create React App dev server neden proje büyüdükçe yavaşlar?

Webpack, bir uygulamayı çalıştırmadan önce tüm bağımlılık grafiğini belleğe alır. Her import ifadesini takip eder, CommonJS modüllerini dönüştürür, loader'ları çalıştırır ve nihayet tek bir ya da birkaç büyük bundle oluşturur. Dev server hazır olduğunda tarayıcı bu bundle'ı alır.

Küçük projelerde bu süreç birkaç saniyeyi geçmez. Proje 50.000 satırın üzerine çıktığında, üçüncü taraf bağımlılıklar şiştiğinde ve node_modules içinde zincirleme dönüşümler başladığında Webpack'in ilk derleme maliyeti giderek artar. CRA'nın önceden yapılandırılmış pipeline'ı bu maliyeti azaltmak için pek az araç sunar; FAST_REFRESH ve cache mekanizmaları yardımcı olsa da temeldeki mimarinin sınırı değişmez.

Sorunu büyüten bir diğer etken, Webpack cache'inin dosya sistemi tabanlı çalışmasıdır. Bağımlılık güncellendiğinde veya ortam değişkeni değiştiğinde cache geçersiz sayılır ve derleme neredeyse sıfırdan başlar. Küçük bir package.json değişikliği bazen 20 saniyelik bir beklemeye yol açabilir; bu da geliştirme günü boyunca birikir.

Vite dev server'da başlama hızı nasıl farklılaşır?

Vite'ın yaklaşımı iki aşamalıdır. İlk aşamada bağımlılıklar, yani node_modules içindeki paketler, esbuild ile önceden paketlenir; bu işlem Webpack'e kıyasla çok daha hızlıdır çünkü esbuild Go diliyle yazılmış ve paralel çalışacak biçimde tasarlanmıştır. İkinci aşamada uygulama kodu hiç paketlenmez; tarayıcı native ES modülleri olarak dosyaları doğrudan talep eder, Vite ise yalnızca talep edilen dosyayı o an dönüştürür.

Bir uygulama ilk kez açıldığında tarayıcı onlarca modülü ayrı ayrı isteyebilir. Bu soğuk açılış zaman zaman CRA'dan daha uzun sürebilir. Asıl kazanım, dev server'ın komut verildiği anda hazır olma süresidir: büyük projelerde CRA'nın 25-30 saniyelik başlangıcı Vite'ta çoğu zaman 1-3 saniyeye iner.

Pratikte şunu hissediyorsunuz: terminal komutu çalıştırıyorsunuz, iki saniye içinde Local: http://localhost:5173 satırını görüyorsunuz ve tarayıcıya geçiyorsunuz. İlk sayfa yüklemesi yavaş gelebilir; bu beklenen bir davranıştır. Vite talep edilmeyen dosyaları önceden işlemediği için tarayıcının ilk ziyarette daha fazla ağ isteği göndermesi gerekir. Dev server hazır, ama tarayıcı tüm modülleri henüz yüklememiştir.

HMR farkı: bir dosya değişikliği neden bu kadar anlam taşır?

Webpack tabanlı HMR, değişen modülü tespit ettikten sonra o modülü ve ona bağımlı tüm modülleri yeniden derleme zincirine sokar. Bağımlılık ağacı derinleştikçe bu zincir uzar. Büyük projelerde küçük bir bileşen değişikliği bile HMR'nin 2-5 saniye sürmesine yol açabilir.

Vite'ta HMR yalnızca değişen modülü tarayıcıya gönderir. Bağımlılık zinciri boyunca yayılma olmaz; her modül bağımsız birimdir. Küçük bir CSS değişikliği veya tek bir bileşen düzenlemesi genellikle 100-300 milisaniye içinde tarayıcıya yansır.

Hız farkı bu kadar. Ama buna eşlik eden bir uyarı var: Vite'ın HMR'si bazı durumlarda bileşen dışı state'i kaybeder. Modül düzeyindeki değişkenler veya global store referansları HMR tetiklendiğinde sıfırlanabilir. CRA'nın React Fast Refresh entegrasyonu bu konuda daha olgun bir geçmişe sahiptir. Bileşenlerin ne zaman yeniden render edildiğini iyi anlamak, bu tür sürprizleri önceden fark etmeye yardımcı olur. HMR'de state kaybı yaşanıyorsa genellikle modül kapsamında tutulan bir değişken ya da doğrudan dosya seviyesinde başlatılan bir store söz konusudur.

Production build: süre ve bundle boyutu ne kadar değişir?

Dev modundaki hız farkı production'a birebir yansımaz. Vite, production build için Rollup kullanır; esbuild değil. Rollup'un tree-shaking ve chunk bölme yetenekleri güçlüdür, ancak esbuild kadar hızlı değildir. CRA'nın Webpack tabanlı production build'iyle kıyaslandığında Vite'ın build süresi genellikle daha kısadır, ama fark dev server kadar belirgin olmaz.

Bundle boyutunda ise pratikte büyük bir fark çıkmaz. Her iki araç da modern tree-shaking, code splitting ve minification uygular. Rollup bazı durumlarda biraz daha küçük çıktı üretebilir; ancak bu fark, import ettiklerinize ve ne kadar dinamik import kullandığınıza bağlı olarak değişir. Hangi kütüphaneleri seçtiğiniz çoğu zaman bundler'ı değiştirmekten daha fazla bundle boyutunu etkiler.

Vite'ta production build'i özelleştirmek için vite.config.ts dosyasında Rollup seçeneklerine doğrudan erişebilirsiniz. Vendor chunk ayrımı, inline threshold ayarları ve CSS code splitting gibi konular ayrı bir konu başlığına taşınacak kadar geniş; burada önemli olan, CRA'da craco veya react-app-rewired olmadan ulaşamadığınız ayarlara Vite'ta doğrudan erişebildiğinizdir.

Geçiş sürecinde öne çıkan engeller

Geçiş tek adımlı değildir. Uygulamanın büyüklüğüne ve bağımlılık yapısına göre birkaç saat ile birkaç gün arasında sürebilir. En sık karşılaşılan engel CommonJS modüllerinden kaynaklanır.

Vite varsayılan olarak ES modüllerini bekler. require() çağrısıyla yüklenen veya module.exports kullanan bazı eski paketler Vite'ın dev server'ında çalışmaz. Esbuild bu paketleri önceden dönüştürmeye çalışır; ama her pakette başarılı olmaz. Özellikle eski tarihli veya Node.js ortamını açıkça varsayan paketler burada sorun çıkarır.

İkinci sık engel ortam değişkenleridir. CRA, REACT_APP_ önekiyle başlayan değişkenleri process.env.REACT_APP_* üzerinden sunar. Vite'ta ise VITE_ öneki gerekir ve değişkenlere import.meta.env.VITE_* üzerinden erişilir. Tüm bileşenlerdeki referanslar güncellenmek zorunda kalır; otomasyon yapsanız da sürprize açık bir alan olarak kalır.

Üçüncü engel CRA'nın özel araçlarıdır. craco, react-app-rewired veya customize-cra ile yapılandırmayı genişlettiyseniz bu katmanı Vite yapılandırmasına taşımak gerekir. Çoğu yapılandırma Vite'ta daha basit biçimde ifade edilebilse de her satırın karşılığı olmayabilir. Birikmekte olan yapılandırma katmanları geçiş maliyetini doğrudan artırır; ne kadar çok özelleştirme yapıldıysa, taşıma o kadar uzun sürer.

Dördüncü engel global CSS ve dosya referanslarıdır. CRA'da bazı projelerde public/index.html'e doğrudan script eklenir, bazı paketler index.html'in belirli bir yapıda olduğunu varsayar. Vite da bir index.html kullanır, ancak bu dosyanın yapısı ve script entegrasyonu farklıdır. Üçüncü taraf eklenti veya iframe senaryoları burada dikkat ister.

Geçiş ne zaman anlamlıdır, ne zaman gereksizdir?

Dev server başlangıcı 5 saniyenin altında olan küçük projelerde geçiş anlamsızdır. Bekleme süresi zaten kısa, HMR farkı milisaniyeler içinde kalıyor ve geçiş için harcanan süre aylarca kazanılacak vakitten fazla olabilir.

Proje 30-40 dosyanın üzerine çıktığında, dev server başlangıcı 10 saniyeyi geçtiğinde ve günlük HMR döngüsü yavaşlamaya başladığında geçiş somut kazanım sağlar. Ekip sabah işe başladığında server'ın hazır olmasını beklemiyorsa, kod-düzenle-gör döngüsü hızlanıyorsa geçiş meyvesini veriyor demektir.

Ters etki de mümkündür. Ağırlıklı olarak CommonJS modüllerine dayanan bir projeyi Vite'a taşımak, kazandığınızdan fazla zaman kaybettirebilir. Geçiş sırasında karşılaşılan uyumluluk sorunları ve dev ortamında ortaya çıkan beklenmedik davranışlar, özellikle büyük ekiplerde geliştirici verimliliğini geçici olarak düşürür. Yayına çıkmadan önce sistematik bir kontrol süreci hazırlamak bu geçişi öngörülebilir kılmaya yardımcı olabilir.

Geçişi daha az riskli hale getiren pratik adımlar

Önce bağımlılık envanterini çıkarın. package.json içindeki her paketi ES modül desteği açısından değerlendirin; hangi paketlerin yalnızca CommonJS sunduğunu listeleyin. Bu liste, geçişin ne kadar süreceğini ve hangi alanların sorunlu olabileceğini önceden gösterir.

Sonra bir branch üzerinde minimal bir vite.config.ts oluşturun ve uygulamanın temel rotasını ayağa kaldırmaya çalışın. Hata mesajları öncelikli engelleri söyler. Ortam değişkenlerini, global CSS import sıralarını ve index.html yapısını bu aşamada ele alın.

Test kapsamı varsa geçiş sırasında testleri çalışır tutmak, davranış değişikliklerini erkenden yakalamak için önemlidir. Vite, Vitest ile doğal uyum içindedir; Jest'ten Vitest'e geçiş ayrı bir iş yükü oluştursa da ilerleyen süreçte ekosistem tutarlılığı sağlar. Test altyapısını ayrı bir adım olarak planlamak genellikle daha iyi sonuç verir.

Geçişi tamamladıktan sonra dev server başlama süresini ve HMR süresini ölçün. Gerçek değerler olmadan geçişin faydalı olup olmadığını söylemek güçtür. Performans kararlarının hangi veriye dayandığı sorusu, araç değişikliği için de geçerlidir; geçiş öncesinde de ölçüm yapılmış olması karşılaştırmayı anlamlı kılar.

CRA, React ekosisteminde uzun yıllar boyunca önemli bir başlangıç noktası oldu. Konfigürasyonsuz çalışma vaadi gerçekti ve yeni projelere hız kazandırdı. Toolchain bu kadar sessiz kalmaz artık; topluluk ve ekosistem Vite etrafında yoğunlaştı, yeni başlayan projelerin büyük çoğunluğu artık Vite ile başlıyor.

Varolan bir projeyi taşımak farklı bir hesap. Geçişin anlamlı olup olmadığı proje büyüklüğüne, bağımlılık yapısına ve günlük geliştirme deneyiminin ne kadar yavaşladığına bağlı. Eğer sabah kahve hazırlanırken dev server'ın başlamasını bekliyorsanız, geçiş büyük ihtimalle karşılığını verir.