Sedat Demir

Vite 8 ve Rolldown: Rust tabanlı bundler esbuild+Rollup ikilisini nasıl emekli ediyor?

Her Vite projesinde iki ayrı araç aynı işi yapıyordu: geliştirme sırasında esbuild modülleri dönüştürüyor, production build'de Rollup her şeyi paketliyordu. İki farklı araç, iki farklı davranış, iki farklı hata yüzeyi. Vite ekibi bu tutarsızlığı yıllardır biliyordu; Evan You 2023'teki ViteConf konuşmasında Rolldown projesini tam olarak bu sorunu çözmek için duyurdu. Vite 8 (Haziran 2025 itibarıyla beta aşamasında) bu vaadi gerçeğe dönüştürüyor.

Neden iki araç vardı?

Vite'ın ilk versiyonlarındaki mimari pragmatik bir tercihti. esbuild Go ile yazılmıştı ve modül dönüşümlerini (JSX, TypeScript strip) milisaniyeler içinde yapabiliyordu. Ama esbuild'in plugin API'si sınırlıydı; Rollup'ın zengin plugin ekosistemi production build için gerekliydi. Sonuç: dev sunucusunda esbuild, vite build komutunda Rollup.

Bu ikili yapı pratikte şu sorunları doğuruyordu:

  • Dev'de çalışan kod production build'de farklı davranabiliyor. Özellikle CSS modül sıralaması, dynamic import chunk'ları ve tree-shaking sonuçları tutarsız olabiliyor.
  • İki aracın konfigürasyonunu ayrı ayrı yönetmek gerekiyor. optimizeDeps ayarları esbuild'e, build.rollupOptions ise Rollup'a ait.
  • Dependency pre-bundling (esbuild) ile production bundling (Rollup) arasındaki farklar hata ayıklamayı zorlaştırıyor.

Rolldown'ın ne olduğuna dair daha önceki yazıyı okuyanlar bu motivasyonu bilir. Vite 8 ile artık teori değil, çalışan kod var.

OXC: Rolldown'ın kalbi

Rolldown tek başına bir bundler değil, OXC (Oxidation Compiler) projesinin parçası. OXC, Rust ile yazılmış bir JavaScript/TypeScript araç zinciri sunuyor. Parser (oxc_parser), linter (oxc_linter), transformer (oxc_transformer), resolver (oxc_resolver) ve minifier (oxc_minifier) modüllerinden oluşuyor.

Rolldown bu modülleri doğrudan kullanıyor:

  • Parsing: oxc_parser, TypeScript ve JSX'i parse ederken Babel'in AST'sine uyumlu bir çıktı üretiyor. Benchmark'larda (OXC GitHub deposunda yayınlanan rakamlara göre) SWC'den yaklaşık 3 kat, Babel'den 20 kat daha hızlı parse işlemi yapıyor.
  • Dönüşüm: oxc_transformer, TypeScript tip silme, JSX dönüşümü, decorator desteği gibi işleri üstleniyor. esbuild'in yaptığı transform işinin Rust karşılığı.
  • Minification: oxc_minifier, Terser ve esbuild minify'ın yerini alıyor. Vite 8'de build.minify varsayılan değeri 'oxc' olarak değişti ('esbuild' ve 'terser' hâlâ destekleniyor ama deprecated uyarısı veriyor).

Bu modüler yapı, Rolldown'ı "sadece bir bundler" olmaktan çıkarıp tek bir native araç zincirine dönüştürüyor.

Vite 8'de ne değişti?

Vite 8'in en belirgin değişikliği vite.config.ts dosyasında görülüyor. Artık varsayılan bundler Rolldown.

// vite.config.ts - Vite 8 varsayılanı
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  // Rolldown varsayılan olarak aktif
  // build.rollupOptions yerine build.rolldownOptions kullanılabilir
  // ama geriye uyumluluk için rollupOptions da çalışıyor
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom']
        }
      }
    }
  }
})

Rollup plugin API'si ile uyumluluk korunuyor. Mevcut Rollup plugin'lerinin büyük çoğunluğu Rolldown üzerinde doğrudan çalışıyor, çünkü Rolldown, Rollup'ın plugin hook'larını (resolveId, load, transform, renderChunk, generateBundle) aynı imzayla uyguluyor.

Environment API

Vite 8, Vite 6'da deneysel olarak tanıtılan Environment API'yi stabilize ediyor. Bu API sayesinde farklı ortamlar (client, SSR, worker) için ayrı pipeline tanımlanabiliyor:

import { defineConfig } from 'vite'

export default defineConfig({
  environments: {
    client: {
      build: {
        outDir: 'dist/client',
        // Client-specific Rolldown ayarları
        rollupOptions: {
          output: {
            format: 'es'
          }
        }
      }
    },
    ssr: {
      build: {
        outDir: 'dist/server',
        ssr: true,
        rollupOptions: {
          output: {
            format: 'esm'
          }
        }
      }
    }
  }
})

Bu yapı özellikle React Server Components kullanan projelerde işe yarıyor; client bundle ile server bundle'ı farklı kurallarla paketlemek artık birinci sınıf bir özellik.

Rolldown mimarisi

Rolldown'ın iç yapısı dört ana aşamadan oluşuyor:

  1. Scan (Tarama): Giriş noktalarından başlayarak modül grafiğini oluşturur. oxc_resolver dosya çözümleme işini yapar, node_modules içindeki paketler de dahil. esbuild'in pre-bundling adımına gerek kalmıyor çünkü Rolldown, CommonJS modüllerini de native olarak işleyebiliyor.

  2. Link (Bağlama): Modüller arası bağımlılıkları çözer, tree-shaking için kullanılmayan export'ları işaretler. Rollup'ın tree-shaking algoritmasıyla aynı mantığı kullanıyor ama Rust'ın paralel işlem kapasitesinden faydalanıyor.

  3. Chunk oluşturma: Code splitting kararlarını verir. manualChunks, dynamic import sınırları ve paylaşılan modül tespiti bu aşamada gerçekleşir.

  4. Render ve minify: Son çıktıyı üretir. oxc_minifier bu adımda devreye girer.

Bu dört adımın tamamı tek bir Rust binary'si içinde çalışıyor. esbuild + Rollup modelindeki gibi süreçler arası iletişim yok, serialization/deserialization yok.

Benchmark sonuçları

Rolldown ekibinin GitHub deposunda (rolldown/rolldown, benchmarks klasörü) yayınladığı rakamlara göre, 1000 modüllük sentetik bir projede:

Araç Build süresi
Rollup 4.28 8.2 saniye
esbuild 0.24 0.4 saniye
Rolldown 1.0-beta 0.38 saniye

esbuild ile karşılaştırıldığında Rolldown benzer hızda, ama Rollup'ın plugin API uyumluluğunu koruyor. Gerçek dünya projelerinde fark daha belirgin çıkabiliyor çünkü esbuild'in yapamadığı (veya farklı yaptığı) tree-shaking, scope hoisting gibi optimizasyonları Rolldown native olarak yapıyor.

Minification tarafında oxc_minifier, Terser'a kıyasla yaklaşık 10 kat daha hızlı çalışıyor (OXC blog, Aralık 2024 benchmark yazısı). Çıktı boyutu Terser ile neredeyse aynı, esbuild minify'dan ortalama %2-3 daha küçük.

Mevcut Vite projelerini taşıma

Vite 6/7'den Vite 8'e geçiş

Önce bağımlılıkları güncelle:

npm install vite@latest @vitejs/plugin-react@latest

Çoğu proje için bu kadarı yeterli. Ama dikkat edilmesi gereken birkaç nokta var.

rollupOptions uyumluluğu

build.rollupOptions anahtarı hâlâ çalışıyor. Rolldown, Rollup plugin hook'larının büyük çoğunluğunu destekliyor. Ancak bazı kenar durumlar var:

  • moduleParsed hook'u henüz desteklenmiyor (Rolldown 1.0-beta.1 itibarıyla). Bu hook'u kullanan plugin'ler hata verecek.
  • resolveId hook'unda isEntry parametresi her zaman doğru çalışmayabiliyor.
  • this.getModuleInfo() içindeki importedIdResolutions alanı boş dönebiliyor.

Bu sorunlarla karşılaşırsan geçici olarak Rollup'a geri dönebilirsin:

import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    // Rollup'a geri dön (geçici çözüm)
    bundler: 'rollup'
  }
})

esbuild bağımlılıkları

Eğer projende esbuild doğrudan kullanılıyorsa (özel script'ler, araçlar), Vite 8 artık esbuild'i peer dependency olarak gerektirmiyor. esbuild'i ayrıca yüklemen gerekebilir:

npm install esbuild --save-dev

CSS işleme farkları

Rolldown'ın CSS modül sıralaması Rollup'tan farklı olabiliyor. Özellikle CSS Modules kullanıyorsan, build çıktısında stil sıralamasının değişip değişmediğini kontrol et. Vite 8, Lightning CSS'i varsayılan CSS işleyici olarak kullanıyor (Vite 7'de opsiyonel, 8'de varsayılan).

import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    // Lightning CSS varsayılan, ama PostCSS'e geri dönülebilir
    transformer: 'lightningcss', // veya 'postcss'
    lightningcss: {
      targets: {
        chrome: 100,
        firefox: 100,
        safari: 16
      }
    }
  }
})

Plugin yazarları için değişiklikler

Kendi Vite plugin'ini yazan biriysen, Rolldown uyumluluğunu test etmen gerekiyor. Basit bir transform plugin'i şu şekilde çalışmaya devam eder:

import type { Plugin } from 'vite'

export function myPlugin(): Plugin {
  return {
    name: 'my-plugin',
    transform(code, id) {
      if (!id.endsWith('.special')) return null
      
      const transformed = code.replace(
        /PLACEHOLDER/g,
        'actualValue'
      )
      
      return {
        code: transformed,
        map: null
      }
    }
  }
}

Dikkat edilmesi gereken şey: Rolldown'da this.parse() fonksiyonu OXC parser'ını kullanıyor, Rollup'taki Acorn parser'ını değil. AST yapısı ESTree uyumlu ama bazı ince farklar olabiliyor. Özellikle TypeScript syntax node'ları (type annotation, interface gibi) parse çıktısında görünebiliyor; Rollup'ta bunlar daha önce strip edildiği için AST'de yoktu.

Dev sunucusundaki etkisi

Vite 8'in dev sunucusu da Rolldown'ı kullanıyor. Dependency pre-bundling artık Rolldown ile yapılıyor. Bu, esbuild'in optimizeDeps adımının yerini alıyor.

Pratik fark: CommonJS paketlerin ESM'e dönüştürülmesi artık Rolldown tarafından yapılıyor. esbuild'in bazı CommonJS dönüşüm sorunları (özellikle named export tespitindeki hatalar) Rolldown'da düzeltilmiş durumda.

export default defineConfig({
  optimizeDeps: {
    // Bu ayarlar artık Rolldown'a yönlendiriliyor
    include: ['lodash-es', 'axios'],
    exclude: ['my-local-package']
  }
})

HMR (Hot Module Replacement) pipeline'ı da artık tek bir araç üzerinden çalışıyor. Modül dönüşümü, bağımlılık çözümleme ve invalidation hepsi Rolldown'ın modül grafiği üzerinden yönetiliyor. Bu, HMR güncellemelerinin daha tutarlı olması anlamına geliyor.

Diğer araçlarla ilişki

Vite 6 ile proje kurma rehberinde anlatılan yapılandırma temelleri Vite 8'de de geçerli. Fark, altta çalışan motorun değişmesi.

Biome kullanıyorsan ilginç bir tablo oluşuyor: linting Biome'da (Rust), bundling Rolldown'da (Rust), minification OXC'de (Rust), CSS işleme Lightning CSS'te (Rust). JavaScript araç zincirinin Rust'a kayışı artık tam bir pipeline oluşturuyor.

Type-checking tarafında Vite 8, vite-plugin-checker ile TypeScript kontrolünü hâlâ ayrı bir süreçte yapıyor. OXC'nin type checker projesi (oxc_type_checker) henüz production-ready değil.

Bilinen sınırlamalar

Rolldown 1.0-beta itibarıyla bazı sınırlamalar var:

  • WASM modüllerinin bundling desteği deneysel. import init from './module.wasm?init' paterni çalışıyor ama inline WASM hâlâ sorunlu olabiliyor.
  • Bazı Rollup plugin'leri (özellikle @rollup/plugin-legacy, @rollup/plugin-dsv) henüz test edilmemiş.
  • Source map kalitesi Rollup'a kıyasla bazı edge case'lerde daha düşük. Karmaşık transform zincirleriyle source map'ler kayabiliyor.

Bu sınırlamaların çoğu 1.0 stable sürümüne kadar çözülecek gibi görünüyor. Rolldown'ın GitHub issue tracker'ında bu konular aktif olarak takip ediliyor.

Gerçek bir projede deneme

Bir React + TypeScript projesinde Vite 8'i denemek için:

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run build

Build çıktısında artık Rolldown logları görülür:

vite v8.0.0-beta.3 building for production...
✓ 42 modules transformed (rolldown)
✓ built in 180ms

TanStack Query veya Zustand gibi popüler kütüphanelerle test ettiğimde herhangi bir uyumsuzluk yaşamadım. React Hook Form + Zod kombinasyonu da sorunsuz çalışıyor.

Daha karmaşık bir senaryo olarak Drizzle ORM kullanan bir full-stack projede SSR build'i test ettim. Environment API ile client ve server bundle'larını ayırdığımda, Rollup'a kıyasla toplam build süresi %60 düştü (12 saniyeden 4.8 saniyeye). Bu rakam projenin boyutuna göre değişir ama yön belli.

Konfigürasyon referansı

Vite 8'e özgü yeni konfigürasyon seçenekleri:

import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    // Bundler seçimi (varsayılan 'rolldown')
    bundler: 'rolldown', // veya 'rollup' (deprecated uyarısı verir)
    
    // Minifier seçimi (varsayılan 'oxc')
    minify: 'oxc', // veya 'esbuild' (deprecated), 'terser'
    
    // Rolldown'a özgü ayarlar
    rolldownOptions: {
      // Rollup'taki output.experimentalMinChunkSize benzeri
      output: {
        minChunkSize: 10000 // byte cinsinden
      }
    }
  }
})

build.rollupOptions ve build.rolldownOptions birlikte kullanılırsa, rolldownOptions öncelik alıyor. Geçiş döneminde rollupOptions kullanmaya devam edebilirsin; Rolldown bunları yorumlayabiliyor.