tsrs ve TypeScript 7: TypeScript Derleyicisinin Rust Portunu Ölçmek
TypeScript 7 derleyicisinin Rust portu tsrs'i tsgo 7.0.2, 7.1 beta ve tsc 5.9 ile dört projede karşılaştırdım: hız, bellek, thread kullanımı ve hata çıktısı.
4 vCPU’lu bir makinede tsrs 0.18.0, dört projede tip kontrolünü TypeScript 7.1 beta’dan 3,9 ila 4,9 kat, TypeScript 7.0.2’den ise 4,8 ila 6,5 kat daha hızlı yaptı. En yüksek bellek kullanımı 7.1 beta’ya göre 2 ila 3 kat, 7.0.2’ye göre 3 ila 4,6 kat daha düşüktü. VS Code kod tabanında (10.427 dosya, 3,5 milyon satır) kontrol süresi TypeScript 7.0.2 ile 32 saniyeden 5,6 saniyeye indi. Hata çıktısı iki projede 7.1 beta ile birebir aynıydı. Diğer iki projede hata konumları ve kodları aynıydı, ancak birkaç mesaj tipleri farklı yazdırıyordu.
Bu sonuçlar tsrs’i şimdiden CI’da, tsc’nin yanında ikinci bir kontrol olarak denemeye değer kılıyor. Ama henüz tam bir yerine geçme anlamına gelmiyor. Yayınlanan sürüm, bir TypeScript geliştirme commit’inin 1.0 öncesi portu. Ayrıca bir sonraki sürümde varsayılan ayarlar değişiyor ve bu, “tsrs hızı” ifadesinin anlamını da değiştiriyor.
Bu yazıda tsrs’in ne olduğunu, nasıl ölçtüğümü, sonuçları ve hızlanmanın nereden geldiğini anlatıyorum. Tüm komutlar yazıda var, böylece sonuçlar başka donanımlarda da kontrol edilebilir.
tsrs Nedir#
tsrs (yeni sekmede açılır), TypeScript 7 derleyicisinin ve language server’ının Rust portu. Oxc projesi (yeni sekmede açılır) altında geliştiriliyor. Cloudflare ve VoidZero, projenin ilk yazarı Max Schwenk ile birlikte çalışıyor. Cloudflare duyurusu (yeni sekmede açılır) çalışmanın TypeScript ekibiyle yakın iş birliği içinde yapıldığını söylüyor ve açıkça “we are not forking TypeScript” diyor.
Önemli olan, neyin port edildiği. TypeScript 7’nin kendisi de bir port: Microsoft JavaScript derleyicisini Go ile yeniden yazdı ve TypeScript 7.0 (yeni sekmede açılır) bu Go derleyicisini normal typescript paketi olarak yayınladı. tsrs ise Go kodunu fonksiyon fonksiyon port ediyor. Uyumluluk sayfası (yeni sekmede açılır) bunu “The Go code is the spec” diye özetliyor. Hata mesajlarında, sıralarında, metinlerinde veya çıkış kodunda görülen her fark bir tsrs hatası sayılıyor.
Bu yüzden tsrs, TypeScript 5’in değil TypeScript 7’nin yerine geçecek şekilde tasarlanmış. TypeScript 7’nin kaldırdığı seçenekler tsrs’te de aynı şekilde reddediliyor. Bu sitenin kendi tsconfig.json dosyası iki derleyicide de aynı hatayla durdu:
tsconfig.json(13,5): error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration.
Yani önce TypeScript 7 geçişi yapılmalı. tsrs, bundan sonra verilecek bir karar.
Nasıl Ölçtüm#
Kurulum, mümkün olduğunca tsrs benchmark metodolojisini (yeni sekmede açılır) izliyor. Aynı sabitlenmiş proje commit’leri ve aynı derleyici bayrakları kullanıldı, sadece ölçek daha küçük.
Makine. 4 vCPU (2,1 GHz Intel Xeon), 15 GB RAM ve Linux x86_64 olan bir bulut VM. Paylaşımlı bir VM, ayrılmış donanıma göre daha gürültülü sonuç verir. Bu yüzden hyperfine (yeni sekmede açılır) ile ölçülen medyan değerleri ve standart sapmayı esas aldım.
Derleyiciler.
| Derleyici | Paket | Not |
|---|---|---|
| tsrs | tsrs@0.18.0-ts7.1.0-dev.20260929 | Yayınlanmış son sürüm; TypeScript b85298b6 commit’ini (7.1 dev) port ediyor |
| tsgo 7.1 beta | typescript@7.1.0-beta | tsrs’in port ettiği koda en yakın resmi sürüm |
| tsgo 7.0.2 | typescript@7.0.2 | Güncel kararlı TypeScript |
| tsc 5.9 | typescript@5.9 | Karşılaştırma için JavaScript derleyicisi |
Native derleyicilerde platform binary’lerini doğrudan çağırdım. Böylece Node başlatıcısının süresi ölçüme girmedi.
Projeler. Üçü, tsrs benchmark kataloğundan, sabitlenmiş commit’leriyle alındı. Dördüncüsü bu site.
| Proje | Dosya | Satır | Tip |
|---|---|---|---|
| sph.sh (Astro sitesi, bu blog) | 866 | 246.452 | 60.106 |
| xstate | 1.536 | 398.462 | 373.803 |
| webpack | 1.607 | 656.348 | 588.331 |
VS Code (src) | 10.427 | 3.510.944 | 2.866.525 |
Dosya ve satır sayılarına node_modules içindeki declaration dosyaları da dahil. Küçük bir sitenin 246 bin satıra ulaşmasının nedeni bu.
Komut. Ölçülen her çalıştırmada aynı bayraklar kullanıldı:
<compiler> -p <project> --noEmit --incremental false --pretty false
Her derleyici kendi varsayılan ayarlarıyla çalıştı. 4 vCPU’da bu, tüm native derleyiciler için 4 checker thread’i demek: tsgo her zaman 4 kullanıyor, tsrs 0.18 ise çekirdek başına bir tane. Yani thread sayısı eşit. Cloudflare yazısının da önerdiği karşılaştırma bu. İkinci turda hepsi --singleThreaded ile çalıştı.
En yüksek bellek kullanımı, GNU time ile ölçülen maksimum resident set size değeri. Üç çalıştırmanın medyanı alındı.
Sonuçlar: Varsayılan Ayarlar#
Süre (medyan; 10 çalıştırma, VS Code’da 5; tsc 5.9 için 2-3 çalıştırma, VS Code’da 1):
| Proje | tsc 5.9 | tsgo 7.0.2 | tsgo 7.1 beta | tsrs 0.18 | tsrs / 7.1 beta | tsrs / 7.0.2 |
|---|---|---|---|---|---|---|
| sph.sh | 3,71 sn | 0,63 sn | 0,52 sn | 0,13 sn | 3,9x | 4,8x |
| xstate | 13,86 sn | 2,48 sn | 1,92 sn | 0,39 sn | 4,9x | 6,3x |
| webpack | 22,23 sn | 4,18 sn | 3,16 sn | 0,65 sn | 4,9x | 6,5x |
| VS Code | 252 sn | 31,99 sn | 22,38 sn | 5,59 sn | 4,0x | 5,7x |
En yüksek bellek (3 çalıştırmanın medyanı; tsc 5.9 tek çalıştırma):
| Proje | tsc 5.9 | tsgo 7.0.2 | tsgo 7.1 beta | tsrs 0.18 | tsrs / 7.1 beta | tsrs / 7.0.2 |
|---|---|---|---|---|---|---|
| sph.sh | 390 MiB | 249 MiB | 194 MiB | 96 MiB | 2,0x az | 2,6x az |
| xstate | 850 MiB | 752 MiB | 578 MiB | 224 MiB | 2,6x az | 3,4x az |
| webpack | 1.294 MiB | 1.258 MiB | 862 MiB | 375 MiB | 2,3x az | 3,4x az |
| VS Code | 8.518 MiB | 8.210 MiB | 5.542 MiB | 1.801 MiB | 3,1x az | 4,6x az |
Bazı gözlemler:
- Mutlak süre açısından en büyük adım hâlâ tsc 5.9’dan TypeScript 7’ye geçiş. VS Code’da bu geçiş 220 saniye kazandırıyor. tsrs bunun üstüne 17 ila 26 saniye daha kazandırıyor. Bu site gibi küçük bir projede tüm native seçenekler bir saniyenin altında bitiyor.
- TypeScript 7.1 beta burada 7.0.2’den 1,2 ila 1,4 kat daha hızlı. Cloudflare yazısına göre bu optimizasyonların bir kısmı tsrs’ten geliyor. tsrs’i sadece 7.0.2 ile karşılaştırmak, güncel TypeScript’e göre farkı olduğundan büyük gösterir.
- CI’da bellek, hızdan daha önemli olabilir. VS Code büyüklüğünde bir kontrol 7.0.2 ile yaklaşık 8 GB, tsrs ile 1,8 GB bellek istiyor. Kontrolün standart bir runner’a sığıp sığmayacağını bu belirliyor.
Sonuçlar: Tek Thread#
--singleThreaded ile her derleyici aynı işi tek çekirdekte yapıyor. Bu, kodun verimliliğini thread kullanımından ayırıyor.
| Proje | tsgo 7.0.2 | tsgo 7.1 beta | tsrs 0.18 | tsrs / 7.1 beta |
|---|---|---|---|---|
| sph.sh | 0,77 sn | 0,67 sn | 0,27 sn | 2,5x |
| xstate | 3,69 sn | 3,03 sn | 1,14 sn | 2,7x |
| webpack | 6,14 sn | 4,90 sn | 1,97 sn | 2,5x |
| VS Code | 57,77 sn | 42,87 sn | 18,90 sn | 2,3x |
Tek çekirdekte tsrs, 7.1 beta’dan yaklaşık 2,5 kat hızlı. VS Code’da tek thread’li tsrs (18,9 sn), dört thread’li tsgo 7.0.2’yi (32 sn) de geçiyor.
Hızlanma Nereden Geliyor#
İki tablo karşılaştırıldığında iki ayrı etki görülüyor. Aşağıdaki paralel hızlanma, tek thread süresinin varsayılan (4 thread) süreye bölümü:
| Proje | tsgo 7.0.2 | tsgo 7.1 beta | tsrs 0.18 |
|---|---|---|---|
| sph.sh | 1,2x | 1,3x | 2,0x |
| xstate | 1,5x | 1,6x | 2,9x |
| webpack | 1,5x | 1,6x | 3,0x |
| VS Code | 1,8x | 1,9x | 3,4x |
Yani 4 çekirdekteki 4-5 katlık fark kabaca iki parçaya ayrılıyor:
- Yaklaşık 2,5 kat, çekirdek başına verimlilikten. Aynı algoritma Go yerine Rust ile çalışıyor. tsrs Rust notları (yeni sekmede açılır) garbage collector yerine thread başına arena’ları, sıkıştırılmış veri yerleşimlerini, mimalloc’u ve profile-guided optimization’ı sayıyor. Ben profil çıkarmadım. Bu yüzden bunu ölçülmüş bir döküm değil, projenin kendi açıklaması olarak okumak gerekir.
- Yaklaşık 1,6 ila 1,9 kat, 4 thread’in daha iyi kullanımından. tsgo, 4 checker ve sabit bir dosya dağılımıyla kontrol yapıyor. 4 çekirdekten 2 katın altında verim alıyor. tsrs 0.18 ise varsayılan olarak locality scheduling, work stealing ve lazy type member özelliklerini ekliyor. Büyük projelerde 3 ila 3,4 kat verim alıyor.
Bir sonraki sürümde değişen, bu ikinci parça.
Varsayılan Davranış Değişiyor#
0.18.0’da tsrs optimizasyonlarını varsayılan olarak çalıştırıyor. 0.19.0 beta adayı bunu tersine çeviriyor. Sürüm notları (yeni sekmede açılır) yeni varsayılanı “the pinned TypeScript defaults: four checkers, Go’s file assignment and checker history, and eager members” olarak tanımlıyor. Scheduling ve bellek optimizasyonları, isteğe bağlı --fast bayrağının veya TSRS_FAST=1 değişkeninin arkasına taşınıyor.
README (yeni sekmede açılır), fast modun ödünleşimlerini sıralıyor:
- Kontrol sırası, bilinen recursive type ve instantiation limit durumlarında hangi hataların çıkacağını değiştirebilir. Çıkış kodu da değişebilir.
- Fast mod daha fazla CPU, daha fazla checker ile de daha fazla bellek kullanabilir.
- Tip ve instantiation sayaçları TypeScript’inkilerden farklı olabilir.
Bu mantıklı bir ayrım. Varsayılan mod birebir uyumluluğu, fast mod ise hızı hedefliyor. Ama bu, yukarıdaki sonuçların 0.19’un varsayılan moduna değil, --fast moduna daha yakın olduğu anlamına geliyor. 0.19’un varsayılan modunun tek thread oranıyla 4 thread oranı arasında bir yere düşmesini beklerim, ama yayınlanmamış bir sürümü ölçmedim. Güncellemeden sonra kendi projenizde ölçmek en doğrusu.
Manşet rakamlar hakkında bir not daha. Upstream benchmark sonuçları (yeni sekmede açılır) tsgo 7.0.2’ye göre 16,9 kata varan hızlanma gösteriyor. Bu ölçümler 16 vCPU’da yapıldı: tsrs 16 checker, tsgo ise varsayılan 4 checker ile çalıştı. Büyük donanımda “ikisi de varsayılan ayarlarda” karşılaştırması olarak bu adil. Ama 4 çekirdekli bir CI runner’ında ikisi de 4 checker kullanıyor ve fark küçülüyor. Makinenin çekirdek sayısı, sonucu derleyici kadar etkiliyor.
Hata Çıktısı: Aynı Hatalar, Bazı Farklı Metinler#
Hata çıktısı farklıysa hızın pek anlamı kalmaz. Her projede tsrs 0.18 ile tsgo 7.1 beta’nın tüm hata çıktısını karşılaştırdım:
| Proje | Hata sayısı (tsrs / 7.1 beta / 7.0.2) | 7.1 beta ile karşılaştırma |
|---|---|---|
| sph.sh | 79 / 79 / 79 | Aynı hatalar; bir açıklama satırı bir tipi farklı yazdırıyor |
| xstate | 0 / 0 / 0 | Byte düzeyinde aynı |
| webpack | 840 / 840 / 848 | 840 hatanın hepsinde dosya, satır, sütun ve kod aynı; 6 mesaj tipleri farklı yazdırıyor |
| VS Code | 371 / 371 / 359 | Byte düzeyinde aynı |
webpack’teki farklar tip yazdırmada. plugins: ModuleFederationPlugin[] gibi uzun bir tip, farklı bir noktada plugins: ... olarak kısaltılıyor. Bazı iç içe açıklama satırları da bir çıktıda var, diğerinde yok. tsgo 7.1 beta ve tsrs, tekrarlanan çalıştırmalarda kendi içinde hep aynı çıktıyı verdi. tsrs 0.18, 7.1 beta etiketini değil, bir 7.1 dev commit’ini port ediyor. Bu farkın bir kısmı o sürüm farkından gelebilir. Bu ölçümlerle iki nedeni birbirinden ayıramıyorum.
7.0.2 ile hata sayıları daha fazla farklı (webpack’te 848’e karşı 840, VS Code’da 359’a karşı 371). tsrs sonuç sayfasına göre, tsrs’in port ettiği commit’ten derlenen typescript@7.1.0-dev.20260930.4 tam olarak tsrs’in hatalarını veriyor. Yani bu fark tsrs’ten değil, TypeScript sürümleri arasındaki değişikliklerden geliyor.
Çoğu ekip için pratik risk dar. Hata mesajı metnini birebir karşılaştıran her şey, örneğin derleyici çıktısının snapshot testleri, bozulabilir. Sadece geçti/kaldı sonucuna bakan bir tip kontrolü çok daha az etkilenir.
Bu Sonuçlarla Ne Yapardım#
- Küçük projeler. Bu site TypeScript 7.1 beta ile 0,5 saniyede kontrol ediliyor. 0,4 saniye kazanmak, ikinci bir derleyiciyi gerekçelendirmiyor.
- Büyük projeler ve monorepo’lar. Burada tsrs CI tablosunu değiştiriyor. VS Code ölçeğindeki kontroller 22-32 saniyeden yaklaşık 6 saniyeye, 5-8 GB bellekten 2 GB’ın altına iniyor. Daha küçük runner’lar seçenek hâline geliyor.
- Nasıl benimsenir. tsrs’i önce ayrı ve engellemeyen bir job olarak çalıştırın,
tsc’yi ana kontrol olarak tutun. Varsayılanlar sürümler arasında değiştiği için tsrs sürümünü tam olarak sabitleyin. Kendi kodunuzda çıkış kodlarının ve hata konumlarının aynı olduğunu kontrol edin. Bu birkaç sürüm boyunca korunursa ana kontrole taşıyın. - Editörler. tsrs bir language server da içeriyor. Burada editör gecikmesini ölçmedim, bu yüzden günlük kullanımda nasıl karşılaştırıldığını söyleyemem.
Oxc araç zinciri linting ve formatting tarafında da aynı yolu izledi. Native araçlar önce mevcut aracın yanında uyumlu olduklarını kanıtlıyor, fark kapandıktan sonra onun yerini alıyor.
Benchmark’ı Tekrarlamak#
Kurulumun tamamı kısa bir script’e sığıyor. Node, git, hyperfine ve GNU time gerekiyor:
mkdir tsbench && cd tsbench
npm init -y >/dev/null
npm i tsrs@0.18.0-ts7.1.0-dev.20260929 \
ts70@npm:typescript@7.0.2 ts71@npm:typescript@7.1.0-beta
TSRS=node_modules/@tsrs/linux-x64-gnu/tsrs
TSGO70=node_modules/@typescript/typescript-linux-x64/lib/tsc
TSGO71=node_modules/ts71/node_modules/@typescript/typescript-linux-x64/lib/tsc
# tsrs bench/projects.json içinde sabitlenen commit
git clone https://github.com/webpack/webpack.git && cd webpack
git checkout b54c5e2aa26dd0267bc904d45402f811f100186c
npx yarn@1.22.22 install --ignore-scripts --ignore-engines
npx yarn@1.22.22 link && npx yarn@1.22.22 link webpack
ARGS="-p . --noEmit --incremental false --pretty false"
# -i: tip hataları 1 veya 2 çıkış koduyla biter, burada bu beklenen durum
hyperfine -N -i --warmup 1 --runs 10 \
-n tsrs "../$TSRS $ARGS" \
-n tsgo-7.0.2 "../$TSGO70 $ARGS" \
-n tsgo-7.1-beta "../$TSGO71 $ARGS"
# En yüksek bellek (KB cinsinden max RSS)
/usr/bin/time -f "%M KB" "../$TSRS" $ARGS > /dev/null
Platform paketlerinin yolları macOS’ta ve musl Linux’ta farklı. Doğru binary için node_modules/@tsrs/ ve node_modules/@typescript/ klasörlerine bakın.
Sonuç#
tsrs ana iddiasını karşılıyor. Eşit thread sayısında, test ettiğim her projede TypeScript 7.1 beta’dan 4-5 kat hızlıydı ve 2-3 kat daha az bellek kullandı. Dört projenin ikisinde çıktı byte düzeyinde aynıydı. Bu kadar genç bir proje için bu kombinasyon alışılmadık. Bunun nedeni, Go derleyicisini spesifikasyon olarak kabul etmesi.
Sınırları da net. Proje 1.0 öncesinde, TypeScript geliştirme commit’lerini takip ediyor ve bir sonraki sürüm varsayılan modun davranışını değiştiriyor. Çok çekirdekli makinelerdeki hızlanmanın büyük kısmı, isteğe bağlı hâle gelen scheduling’den geliyor. Büyük kod tabanlarında şimdiden tsc’nin yanında çalıştırmaya değer. Küçük projelerde ise TypeScript 7 tek başına yeterli.
Kaynaklar#
- tsrs on GitHub (yeni sekmede açılır) - Rust portunun kaynak kodu, README ve fast mod dokümantasyonu
- A Rust port of TypeScript (Cloudflare Blog) (yeni sekmede açılır) - Motivasyonu, TypeScript ekibiyle iş birliğini ve manşet rakamları anlatan duyuru
- tsrs compatibility and evidence (yeni sekmede açılır) - Uyumluluk sayıları, “Go kodu spesifikasyondur” kuralı ve bilinen eksikler
- tsrs release notes (yeni sekmede açılır) - Varsayılan checker ayarlarındaki değişiklik dahil 0.18.0 ve 0.19.0 aday notları
- tsrs benchmark methodology (yeni sekmede açılır) - Sabitlenmiş projeler, derleyici bayrakları ve upstream benchmark’ların nasıl çalıştığı
- tsrs benchmark results (yeni sekmede açılır) - tsgo 7.0.2 ve bun check ile 16 vCPU üzerindeki upstream sonuçlar
- tsrs Rust implementation notes (yeni sekmede açılır) - Bellek modeli ve derleme düzeyindeki optimizasyonlar: arena’lar, sıkıştırılmış yerleşimler, mimalloc, PGO
- tsrs usage and performance options (yeni sekmede açılır) - Checker sayıları, bellek hedefleri ve fast modun yan etkileri
- Announcing TypeScript 7.0 (yeni sekmede açılır) - Go tabanlı TypeScript derleyicisinin resmi sürüm duyurusu
- A 10x Faster TypeScript (yeni sekmede açılır) - Native Go portunun ilk duyurusu
- microsoft/typescript-benchmarking (yeni sekmede açılır) - TypeScript ekibinin kullandığı benchmark paketi, sabitlenmiş projelerin bir kısmının kaynağı
- hyperfine (yeni sekmede açılır) - Tüm süre ölçümlerinde kullanılan komut satırı benchmark aracı
- Oxc (yeni sekmede açılır) - tsrs’e ev sahipliği yapan JavaScript araç zinciri projesi
İlgili yazılar
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.
esbuild · build-tools · vite +4
Nub ve Vite+, 2026'nın oxc tabanlı iki Rust araç zinciri; rakip gibi görünüp öyle değiller. Hangi ikilinin hangi repoda yeri olduğuna dair net bir kural.
javascript · typescript · vite +3
Google'ın 2009'da çıkardığı Closure Compiler'ın modern web araçlarını nasıl şekillendirdiğini ve bugünkü build araçlarına kalıcı etkisini inceliyoruz.
javascript · build-tools · best-practices +6
CDK TypeScript Lambda için 9 bundler ve 3 cdk synth runner'ının ölçümlü karşılaştırması; her katman için varsayılan ve onu seçtiren kural.
aws-cdk · lambda · typescript +3
DI container'lar, monolitik SDK'lar, god-handler'lar, modül üstü secret çağrıları ve ağır ORM'ler: soğuk başlatmada bedeli ve yerine geçen fonksiyonel yapı.
lambda · typescript · serverless +2