İçeriğe atla

esbuild, SWC ve Vite: Native Araçlar Webpack'in Yerini Neden Aldı

esbuild, SWC ve Vite gibi native tool'ların webpack'in hız sorunlarını nasıl çözdüğü: build süreleri saniyelerden milisaniyelere böyle indi.

Ayhan Sipahi Ayhan Sipahi

webpack gibi JavaScript tabanlı bundler’lar sert bir performans tavanına çarptı: single-threaded çalışma, dosya başına AST parsing ve garbage collection duraklarıyla büyük React uygulamalarında production build’leri 60 saniyeyi aştı. Yavaş feedback döngüleri developer odağını kırıyor ve her merge’de CI maliyetlerini şişiriyor. esbuild, SWC ve Vite bu tavanı, kritik yolu native derlenmiş koda taşıyarak aştı.

Zorluklar takımlar büyüdükçe arttı. Build zamanları her şey için darboğaz haline geldi: local development, CI/CD pipeline’ları ve deployment processleri. Geliştirme takımları kod yazmaktan çok build beklemekle vakit geçiriyordu.

Frontend tooling’deki performans devrimini ateşleyen baskı buydu: JavaScript tabanlı tool’lardan native derlenmiş olanlara doğru bir kayış.

Webpack Performance Tavanı (2016-2018)#

Performans devriminin neden kaçınılmaz olduğunu anlamak için webpack’in temel kısıtlarını anlamanız gerekiyor.

JavaScript Overhead#

JavaScript ile yazılmış olan webpack’in doğal performans limitasyonları vardı:

// webpack'in her modül için kabaca yaptığı şey bu
function processModule(source, loaders) {
  let result = source;
  
  // Her loader'ı sırayla uygula
  for (const loader of loaders) {
    result = loader.process(result);
  }
  
  // AST ile parse et (pahalı)
  const ast = parser.parse(result);
  
  // AST'yi transform et (pahalı)
  const transformed = transformer.transform(ast);
  
  // Kod generate et (pahalı)
  return generator.generate(transformed);
}

Her operasyon pahalıydı:

  • Her dosya için AST parsing
  • Birden fazla string transformation
  • Node.js I/O overhead
  • Garbage collection pause’ları
  • Çoğu operasyon için single-threaded execution

Bedel Nerede Görünüyordu#

Büyük bir kod tabanında bu maliyet öngörülebilir şekilde birikiyordu. Soğuk dev server başlangıcı onlarca saniyeyi buluyor, tam bir production build bir dakikayı aşabiliyordu. Incremental rebuild’ler daha kısaydı ama yine de dikkati bölecek kadar uzundu.

Asıl pahalı olan kısım dikkatti:

  • Developer’lar beklerken başka bir işe geçiyor, sonra bağlamı yeniden kurmanın bedelini ödüyordu
  • Build bittiğinde, cevabı aranan soru çoktan bayatlamış oluyordu
  • CI pipeline’ları kuyruğa dönüştü; her merge tam build maliyetini ödüyordu
  • Local development, derlenen dillerin toolchain’lerinin yanında hantal kalıyordu

Bundle Size Problemi#

webpack’in optimizasyon yaklaşımı kendi problemlerini yarattı:

// Tree shaking ile bile, bu...
import { debounce } from 'lodash';

// ...hala gerekenden çok daha fazla kod include ediyordu
// çünkü webpack fonksiyon seviyesinde optimize edemiyordu

Büyük uygulamalar “optimizasyon”dan sonra bile multi-megabyte bundle’larla sonuçlanıyordu. Bireysel parçaları çözmek için tool’lar vardı (code splitting, tree shaking, minification), ama hepsi yavaş ve doğru configure etmesi zordu.

Parcel ve Zero-Config Vaadi (2017)#

Devon Govett Parcel’ı basit bir vaatle yayınladı: “Blazingly fast, zero configuration web application bundler.”

Configuration Olmamasının Çekiciliği#

// webpack.config.js gerekmez
// Sadece çalıştır: parcel index.html

// Parcel otomatik olarak şunları yapardı:
// - Dosya tiplerini detect edip transformation'ları uygula
// - Dynamic import'larda kodu split et
// - Production için optimize et
// - Source map'ler generate et
// - Farklı asset tiplerini handle et

Developer experience anında daha iyiydi:

  • Yeni projeler ilk komuttan saniyeler sonra ayaktaydı
  • Configuration yok demek daha az bug ve tutarsızlık demekti
  • Otomatik optimizasyonlar expertise olmadan daha iyi performans demekti

Hız Nereden Geliyordu#

Parcel’ın kazanımının kaynağı mimarisiydi. Transform’ları worker processlerle CPU çekirdeklerine dağıtıyor, derlenmiş asset’leri diskte cache’liyordu; böylece ikinci build birincinin çoğunu yeniden kullanıyordu. Çok çekirdekli makinelerde bu, webpack’in büyük ölçüde single-threaded pipeline’ını geride bırakıyordu. Yine de iki tool da parse ve transform işini JavaScript içinde yapıyordu; yani tavan aynı tavandı, sadece biraz daha uzaktaydı.

Parcel’ın Sınırları#

Vaat etmesine rağmen, Parcel scaling sorunlarıyla karşılaştı. Custom davranışa ihtiyaç duyulduğu anda Parcel’ın “zero-config” felsefesi bir limitasyona dönüştü; hâlâ JavaScript ile yazıldığı için de büyük projelerde webpack’inkine benzer performans duvarlarına çarptı. webpack’in olgun plugin ekosistemini değiştirmek zordu, bu yüzden specific loader’lara ihtiyaç duyan projeler Parcel’da bunları bulamadı. Erken versiyonlardaki güvenilirlik sorunları da takımları production’da kullanmakta tereddüde düşürdü.

Native Tool’lar Devrimi (2019-2021)#

Gerçek performans breakthrough, developer’lar build tool’larını compiled dillerde yazmaya başladığında geldi.

esbuild’in Go Bahsi (2020)#

Evan Wallace’ın esbuild’i, build tool’larının kat kat daha hızlı olabileceğini kanıtladı:

# esbuild'in yayınladığı benchmark: three.js'in 10 kopyası,
# minify edilmiş ve source map'li bir production build
esbuild:             0.39s
parcel 2:           14.91s
rollup 4 + terser:  34.10s
webpack 5:          41.21s

# Bu iş yükünde kabaca iki büyüklük mertebesi

esbuild bunu nasıl başardı:

  1. Go ile yazıldı: Native machine code’a compile edildi
  2. Parallelization: Parallel processing için goroutine’lerin yoğun kullanımı
  3. Minimal AST: Sadece bundling için gerekli olanı parse eder
  4. Memory verimliliği: Garbage collection pause’ları olmadan dikkatli memory yönetimi
  5. Basit architecture: Her edge case değil, %80 use case’e odaklandı

SWC’nin Rust Yaklaşımı (2019)#

kdy1’in SWC’si (Speedy Web Compiler) farklı bir yaklaşım aldı:

// SWC'nin Rust architecture'sı şunları mümkün kıldı:
// - Zero-cost abstraction'lar
// - GC olmadan memory safety
// - Fearless concurrency

// SWC'nin kendi iddiası: tek thread'de Babel'den 20x,
// dört çekirdekte 70x daha hızlı

Rust’ın ownership modeli SWC’ye memory safety kazandırdı; tüm bug sınıflarını baştan eledi. Plugin sistemi, JavaScript tabanlı transform plugin’lerinden daha güvenilir çıktı ve native TypeScript parsing’i tsc’den çok daha hızlı çalıştı. Next.js gibi büyük framework’ler onu production’da kullanmaya başladı.

10x-100x Performance Farkı#

esbuild’in dokümantasyonu, JavaScript bundler’larıyla arasındaki farkı 10-100x olarak koyuyor ve arkasındaki aritmetik gizemli değil. Derlenmiş bir binary, Node.js’in her dosya için ödediği parse, allocate ve garbage collect döngüsünü atlıyor; üstelik tek çekirdek yerine bütün çekirdekleri doyuruyor.

Oranın kendisinden çok farkın büyüklüğü önemli. 60 saniyelik bir build’i 40 saniyeye indirmek bir planlama iyileştirmesidir. Aynı build’i bir saniyenin altına çekmek beklemeyi akıştan tamamen çıkarır; bu da developer’ın denemeye razı olduğu şeyleri değiştirir.

Vite’ın Development/Production Ayrımı (2020)#

Evan You, Vite’ı radikal bir kavrayışla yarattı: development ve production build’leri farklı stratejiler kullanmalı.

ES Modules Kavrayışı#

// Development için her şeyi bundle etmek yerine...
import { createApp } from 'vue'
import App from './App.vue'

// Vite modülleri native ES modülleri kullanarak ayrı ayrı serve eder
// Browser modül loading'i handle eder
// Sadece değişen modüller re-compile edilir

Bu şunları mümkün kıldı:

  • Anında server start: Başlangıçta bundling yapılmıyor
  • Hızlı HMR: Sadece değişen modül güncellenir
  • Daha kolay debugging: Browser, yazdığınız modül grafiğine çok yakın bir grafiği yüklüyor; stack trace’ler kaynak dosyalarla örtüşüyor

Hibrit Yaklaşım#

// Development: Native ES modülleri
vite dev  // ~400ms'de başlar

// Production: Rollup bundling
vite build  // Deployment için optimize edilmiş bundle

Bu, development hızı ile production optimizasyonu arasındaki yanlış seçimi çözdü.

Framework Integration#

Vite modern framework’ler için tercih edilen build tool’u haline geldi:

// Vue 3
npm create vue@latest

// React
npm create vite@latest my-app -- --template react

// Svelte
npm create vite@latest my-app -- --template svelte

Her template out of the box çalışan mantıklı default’larla geliyordu.

Framework-Integrated Tooling (2018-Şimdi)#

Aynı zamanda, framework’ler sofistike build tool’larını doğrudan integrate etmeye başladılar.

Next.js Kendi Tooling’ini Paketliyor#

// Next.js 9+ şunları include ediyordu:
// - Otomatik code splitting
// - CSS-in-JS optimizasyonu  
// - Image optimization
// - API route'ları
// - Built-in TypeScript desteği
// - Fast refresh (React hot reloading)

// Hepsi sıfır configuration ile:
npx create-next-app my-app
cd my-app
npm run dev  // Sadece çalışır

Productivity etkisi büyüktü:

  • React projesi başlatmak, elle kurulan bir config yerine tek komuta indi
  • Production optimizasyonları varsayılan olarak geliyor, bakımını framework ekibi üstleniyordu
  • Performance pratikleri tool’la birlikte geliyordu; her proje bunları yeniden keşfetmek zorunda kalmadı

Vue CLI’ın Opinionated Kurulumu#

# Vue CLI şunları sağladı:
vue create my-project

# Interactive setup ile:
? Please pick a preset: Manually select features
? Check the features needed for your project:
 Babel
 TypeScript  
 Router
 Vuex
 CSS Pre-processors
 Linter / Formatter
 Unit Testing
 E2E Testing

Create React App’in Tek Komutluk Kurulumu#

// CRA'nın felsefesi: 
// - Bir dependency her şeyi yönetir
// - Use case'lerin %90'ı için mantıklı default'lar
// - Advanced customization için eject opsiyonu

npx create-react-app my-app
cd my-app
npm start  // Mükemmel development deneyimi
npm run build  // Optimize edilmiş production build

Trade-off’lar netti:

  • Pro: Sıfır configuration, her zaman güncel tooling
  • Con: Eject etmeden sınırlı customization
  • Impact: React development’ı demokratikleştirdi

Snowpack Deneyi (2020-2021)#

Fred K. Schott’un Snowpack’i daha da radikal bir yaklaşımı araştırdı: hiç bundle etmezsek ne olur?

O(1) Build Tool#

// Snowpack'in kavrayışı: 
// Build zamanı proje boyutundan bağımsız olarak sabit olmalı

// Geleneksel bundler'lar: O(n) burada n = modül sayısı
// Snowpack: Bundle etmekten tamamen kaçınarak O(1) build zamanı

Nasıl çalışıyordu:

  1. Her dosyayı ayrı ayrı transform et
  2. Native ES modülleri kullanarak dosyaları serve et
  3. Browser’ın dependency resolution’ı handle etmesine izin ver
  4. Birden fazla dosya request’ini efficiently handle etmek için HTTP/2 kullan

Unbundled Development’ın Avantajları#

Burada asıl ilginç olan, maliyet eğrisinin şekliydi. Başlangıçta tüm modül grafiğini gezmek gerekmediği için büyük bir kod tabanı da küçüğü kadar hızlı açılıyordu. Tek satırlık bir değişiklik tek dosyayı yeniden transform ediyordu. Memory kullanımı da aynı nedenle sabit kalıyordu: bellekte tutulan bütün bir bundle grafiği yoktu.

Snowpack’in Sınırları#

Etkileyici performansa rağmen, Snowpack adoption zorluklarıyla karşılaştı:

Ekosistem Integration: Birçok tool bundled kod bekliyordu ve unbundled development ile çalışmıyordu.

Production Hikayesi: Development hızlıyken, production build’leri optimal performans için hâlâ bundling’e ihtiyaç duyuyordu.

Browser ve Network Sınırları: Tüm browser’lar karmaşık uygulamalar için ES modüllerini yeterince iyi desteklemiyordu; HTTP/2 ile bile yüzlerce ayrı modülü yüklemenin bir latency maliyeti vardı.

Turbopack, Next.js’in Rust Bundler’ı (2022)#

Vercel’in Turbopack’i bu çizginin son halkası: React development için özel olarak tasarlanmış, Rust ile yazılmış bir tooling.

Webpack Replacement Stratejisi#

// Turbopack'in yaklaşımı:
// - Rust ile yazıldı, native binary'ye derleniyor
// - React/Next.js için özel olarak tasarlandı
// - Incremental compilation architecture
// - Function-level caching
// - Lazy bundling: sadece dev server'ın istediği kadarı
// - Derleme çıktıları çalıştırmalar arasında diske yazılıyor

Incremental Architecture#

// Turbopack'in temel kavrayışı: her fonksiyonu cacheable olarak ele al
fn transform_module(input: &str) -> Result<String> {
    // Bu fonksiyon otomatik olarak memoize ediliyor
    // Input değişmediyse, cached result'ı döndür
    // Sadece gerçekten değişeni yeniden compute et
}

Deneyden Varsayılana#

Vercel’in lansman benchmark’larındaki çarpanlar diğer tool yazarlarından hemen itiraz gördü; o başlık rakamlarını pazarlama olarak okumak doğru olur. Kalıcı iddia daha dar ve daha kullanışlı: Turbopack, JavaScript darboğazını Next.js dev döngüsünden çıkarıyor ve rebuild maliyetini projenin değil değişikliğin boyutuyla orantılı hale getiriyor. Tartışmayı adoption ile kazanmasına bu yetti. Turbopack artık Next.js’in varsayılan bundler’ı; webpack bir flag’in arkasında duruyor.

Saniyenin Altındaki Build’ler Neyi Değiştirdi#

Kabaca bir saniyenin altında, build süresi developer’ların etrafında plan yaptığı bir şey olmaktan çıkıyor. Bu eşiği geçmek, işin nasıl yürüdüğünü yeniden düzenledi.

Geri Bildirim Döngüsünü Geri Kazanmak#

Build’ler sub-second olduğunda, developer’lar build zamanları hakkında düşünmeyi bırakır. Feedback anında geldiğinde daha fazla yaklaşım denerler, değişiklikleri batch’lemek yerine hipotezleri anında test ederler ve development processi daha akışkan hale gelir.

Compiler-as-Service Modeli#

Modern tool’lar one-off processler yerine persistent servisler olarak çalışır:

// Eski model: Her seferinde cold start
$ webpack build  // Her şeyi sıfırdan parse et

// Yeni model: Persistent, incremental compilation  
$ vite dev  // Compiler'ı warm tut, sadece değişeni rebuild et

Framework Fragmentation Zorluğu (2021-Şimdi)#

Performance problemleri çözülürken, yeni bir sorun ortaya çıktı: her framework kendi optimize edilmiş tooling’ini istiyordu.

Tool’ların Çoğalması#

// React ekosistemi:
Create React App, Next.js, Vite, Remix

// Vue ekosistemi:  
Vue CLI, Nuxt, Vite, Quasar

// Svelte ekosistemi:
SvelteKit, Vite, Snowpack

// Angular ekosistemi:
Angular CLI, nx, Bazel

Universal Tool Zorluğu#

Universal tool’lar yaratma denemeleri trade-off’larla karşılaştı:

Vite: Development için mükemmel, ama her framework farklı production optimizasyonlarına ihtiyaç duyuyordu.

esbuild: Blazingly fast, ama framework-specific feature’lar için sınırlı plugin ekosistemi.

Turbopack: Maximum performance, ama Next.js ekosistemine coupled.

Build Tooling’in 2025’teki Durumu#

2025’e kadar, performance problemi büyük ölçüde çözüldü. Şimdi sahip olduklarımız:

Performance Katmanları#

# Tool kuşağına göre kabaca dev server başlangıcı:
Katman 1 (Native): <500ms (Vite, esbuild)
Katman 2 (Optimize JS): 1-3s (webpack 5)  
Katman 3 (Legacy): 5-15s (webpack 4, eski config'ler)

# Hot reloading:
Katman 1: <100ms
Katman 2: 200-500ms
Katman 3: 1-5s

Yeni Zorluklar#

Performance çözülünce, yeni zorluklar ortaya çıktı. Framework seçmek giderek tüm tooling ekosistemini seçmek anlamına geliyor; tool’lar daha hızlı olsa da karmaşık use case’ler için configure etmek mutlaka daha basit değil. Native tool’lara geçiş de yeni bir dependency karmaşıklığı yarattı: Rust toolchain’leri ve Go binary’leri. Hızlı compilation ise debugging’i zorlaştırdı, çünkü problemler gözlemlenemeyecek kadar hızlı geçiyor.

Performans Devriminin Dersleri#

2019-2022 çalkantısından dört prensip ayakta kaldı.

Native tool’lar karmaşıklığının bedelini ödüyor. 10x-100x’lik bir iyileşme, artık kurulu ve güncel tutmanız gereken Rust ve Go toolchain’lerinin faturasını karşılıyor.

Development ve production farklı strateji kullanabilir. Vite’ın merkezi bahsi doğru çıktı; bugün neredeyse her modern tool aynı ayrımı yapıyor.

Framework’e gömülü tooling genelde kazanıyor. Next.js, Nuxt ve SvelteKit tek bir pattern kümesine göre ayarlanmış bir build kurulumu getiriyor; bu da çoğu takım için universal tool’ları geride bırakıyor.

Hız yeni pattern’lerin önünü açıyor. Anlık feedback döngüleri, agresif hot reloading ve live preview özellikleri ancak rebuild developer fark etmeden bittiğinde makul hale geliyor.

Hızın Getirdikleri#

Build süresi yoldan çekilince kısıtlar başka yerlere kaydı:

  • Edge computing: Kullanıcıya yakın çalışacak şekilde build edilip deploy edilen uygulamalar
  • Type safety: Katı TypeScript kurulumlarını pratik kılacak kadar hızlı compilation
  • Deployment optimizasyonu: Her branch için ayrı preview’ı ekonomik hale getiren build hızı
  • AI integration: Editör döngüsünün içine sığacak kadar hızlı tooling

Yeni bir projede varsayılan, native çekirdekli bir tool: stack framework’ten bağımsızsa Vite, zaten Next.js ya da SvelteKit içindeyseniz framework’ün kendi bundler’ı. JavaScript tabanlı bir pipeline’a ancak belirli bir webpack plugin’inin karşılığı yoksa ve onu yeniden yazmak yavaş build’den pahalıya geliyorsa dönün.

Kaynaklar#

Frontend Tooling'in Evrimi: Bir Developer'ın Perspektifi

jQuery dosya birleştirmesinden Rust-powered bundler'lara - frontend tooling'in gerçek production problemlerini nasıl çözmek için evrildiğinin anlatılmamış hikayesi, öğrenilen dersler ve pratik deneyimlerle.

İlerleme 3/4 yazı tamamlandı

İlgili yazılar