Rust ile WebAssembly Geliştirme Ortamı Kurulumu
Rust ile WebAssembly geliştirmeye girişmek, ilk bakışta karmaşık bir toolchain kurulumu gibi görünebilir. Ama bir kez doğru temeli attın mı, bu ikili gerçekten güçlü bir kombinasyon sunuyor. Özellikle edge computing senaryolarında, CDN edge node’larında ya da tarayıcıda near-native performans gerektiren uygulamalarda Rust + WASM ikilisi rakipsiz.
Bu yazıda sıfırdan başlayarak tam anlamıyla çalışan bir Rust/WASM geliştirme ortamı kuracağız. Sadece “hello world” değil, gerçek dünyada kullanabileceğin, hot-reload destekli, test edilebilir bir yapı hedefliyoruz.
Neden Rust ve WebAssembly?
C ve C++ dışında WebAssembly’e derlenen diller içinde Rust, en olgun ekosisteme sahip olan. Bunun arkasında birkaç somut neden var.
wasm-bindgen kütüphanesi sayesinde JavaScript ile Rust arasındaki köprü inanılmaz derecede temiz. String, closure, Promise, DOM nesneleri… bunların hepsini elle byte dizilerine çevirmek zorunda kalmıyorsun. Araç zinciri bunu senin için hallediyor.
Bellek güvenliği konusunda Rust’ın getirdiği garantiler WASM tarafında da geçerli. Garbage collector yok, runtime overhead yok. Bu da özellikle Cloudflare Workers, Fastly Compute@Edge gibi ortamlarda ciddi bir avantaj.
Bir de şu var: Rust’ın paket yöneticisi Cargo, WASM toolchain’i ile mükemmel entegre çalışıyor. NPM dünyasında yaşayan birisine biraz yabancı gelebilir ama bir kez alıştın mı, geri dönmek istemiyorsun.
Sistem Gereksinimleri ve Ön Hazırlık
Geliştirme ortamı olarak Ubuntu 22.04 LTS ya da Fedora 38+ üzerinde çalıştığını varsayıyorum. macOS için adımların büyük bölümü aynı, sadece paket yöneticisi farklı. Windows kullanıyorsan WSL2 üzerinden gitmeni şiddetle tavsiye ederim.
Başlamadan önce sisteminde şunların olduğundan emin ol:
- curl veya wget (Rust kurulumu için)
- build-essential veya eşdeğeri (gcc, make)
- Node.js 18+ (wasm-pack ve webpack için)
- git (tabii ki)
Ubuntu/Debian üzerinde eksikleri tamamlamak için:
sudo apt update && sudo apt install -y
curl
build-essential
pkg-config
libssl-dev
git
nodejs
npm
Fedora/RHEL için:
sudo dnf groupinstall "Development Tools" -y
sudo dnf install -y curl openssl-devel pkg-config nodejs npm git
Rust Kurulumu: rustup ile Doğru Yol
Rust’ı dağıtımın paket yöneticisinden kurma. Neden? Çünkü Rust toolchain versiyonları hızlı değişiyor ve WASM hedefi için spesifik bileşenlere ihtiyacın var. rustup her şeyi versiyonlanmış şekilde yönetiyor.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Kurulum sırasında seçenek soracak. Çoğu durumda 1) Proceed with installation (default) yeterli. Kurulum bittikten sonra shell’ini yenile:
source "$HOME/.cargo/env"
Versiyonu doğrula:
rustc --version
cargo --version
Şu an muhtemelen stable channel’ındasın. Bu iyi. WASM geliştirme için stable Rust uzun zamandır yeterli.
WASM Hedefini Eklemek
Rust derleyicisi çapraz derleme yapabilmek için hedef mimarilere ihtiyaç duyuyor. WebAssembly için wasm32-unknown-unknown hedefini ekliyoruz:
rustup target add wasm32-unknown-unknown
Eğer WASI (WebAssembly System Interface) ile de çalışacaksan, yani server-side WASM senaryoları için:
rustup target add wasm32-wasi
İkisi de olsun, yer kaplamaz.
wasm-pack Kurulumu
wasm-pack, Rust ve JavaScript dünyası arasındaki en kritik köprü araç. Rust kodunu WASM’a derliyor, gerekli JavaScript wrapper’larını otomatik oluşturuyor, npm paketi formatında çıktı üretiyor. Bir sysadmin mantığıyla düşünürsen: bu araç olmazsa her şeyi elle yapmak zorunda kalırsın.
cargo install wasm-pack
Bu işlem birkaç dakika sürebilir, Rust’tan derleniyor. Sabır.
Kurulum tamamlandığında:
wasm-pack --version
wasm-pack 0.12.x gibi bir çıktı görmelisin.
wasm-bindgen-cli
wasm-pack çoğu durumu halleder ama bazen daha granüler kontrol isteyebilirsin. O zaman wasm-bindgen-cli de lazım:
cargo install wasm-bindgen-cli
Kritik not: wasm-bindgen-cli versiyonu, projedeki wasm-bindgen crate versiyonuyla eşleşmek zorunda. Versiyon uyuşmazlığı yaşarsan garip hatalar alırsın. Cargo.toml dosyanda ne versiyonu kullandığına dikkat et.
cargo-generate ile Proje Şablonu
Sıfırdan proje oluşturmak yerine, Rust topluluğunun hazırladığı şablonlarla başlamak zaman kazandırır. cargo-generate aracı, GitHub’daki şablonlardan yerel proje oluşturur:
cargo install cargo-generate
wasm-pack team’in resmi şablonunu kullanalım:
cargo generate --git https://github.com/rustwasm/wasm-pack-template --name my-wasm-project
cd my-wasm-project
Bu şablon sana şu yapıyı verir:
src/lib.rs: Ana Rust kaynak dosyasıCargo.toml: Bağımlılık ve metadata yönetimitests/web.rs: Browser ortamında çalışan testler.gitignore: WASM çıktılarını ignore eder
İlk Gerçek Proje: Sayı İşlemleri Kütüphanesi
Teoriden çıkalım. Diyelim ki frontend ekibin CPU-yoğun bir işlemi JavaScript’ten Rust’a taşımak istiyor. Büyük veri setleri üzerinde istatistiksel hesaplamalar yapan bir kütüphane yazalım.
src/lib.rs dosyasını şöyle düzenle:
use wasm_bindgen::prelude::*;
// JavaScript'ten çağrılabilir fonksiyon
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => {
let mut a = 0u32;
let mut b = 1u32;
for _ in 2..=n {
let temp = a + b;
a = b;
b = temp;
}
b
}
}
}
// Büyük bir vektör üzerinde ortalama hesapla
#[wasm_bindgen]
pub fn calculate_mean(data: &[f64]) -> f64 {
if data.is_empty() {
return 0.0;
}
let sum: f64 = data.iter().sum();
sum / data.len() as f64
}
// Standart sapma
#[wasm_bindgen]
pub fn calculate_std_dev(data: &[f64]) -> f64 {
if data.len() < 2 {
return 0.0;
}
let mean = calculate_mean(data);
let variance: f64 = data.iter()
.map(|x| (x - mean).powi(2))
.sum::<f64>() / (data.len() - 1) as f64;
variance.sqrt()
}
Cargo.toml dosyasını düzenle:
[package]
name = "my-wasm-project"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2"
console_error_panic_hook = { version = "0.1", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3"
[profile.release]
opt-level = "s"
lto = true
opt-level = "s" boyut optimizasyonu demek. lto = true ise Link Time Optimization, WASM dosyasının küçülmesine ciddi katkı sağlar.
Derleme ve Çıktı İnceleme
Projeyi derleyelim:
# Web ortamı için (varsayılan)
wasm-pack build --target web
# Node.js için
wasm-pack build --target nodejs
# Bundler (webpack, rollup) için
wasm-pack build --target bundler
pkg/ dizini oluşturulacak. İçeriğine bak:
ls -la pkg/
Şunları göreceksin:
my_wasm_project_bg.wasm: Asıl WASM binary’simy_wasm_project.js: JavaScript glue kodumy_wasm_project.d.ts: TypeScript tip tanımlarıpackage.json: npm paketi olarak kullanmak için
TypeScript tanımlarının otomatik oluşturulması büyük bir nimet. Frontend geliştirici meslektaşın tip güvenli bir şekilde Rust fonksiyonlarını çağırabilir.
JavaScript ile Entegrasyon
Basit bir test sayfası oluşturalım. Proje kökünde bir www/ dizini aç:
mkdir www && cd www
npm init -y
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev
npm install ../pkg
www/index.js dosyası:
import init, { fibonacci, calculate_mean, calculate_std_dev } from 'my-wasm-project';
async function run() {
// WASM modülünü başlat
await init();
// Fibonacci testi
console.log('Fibonacci(40):', fibonacci(40));
// İstatistik testi - 100.000 elemanlı dizi
const bigArray = new Float64Array(100000);
for (let i = 0; i < bigArray.length; i++) {
bigArray[i] = Math.random() * 1000;
}
const start = performance.now();
const mean = calculate_mean(bigArray);
const stdDev = calculate_std_dev(bigArray);
const elapsed = performance.now() - start;
console.log(`Ortalama: ${mean.toFixed(4)}`);
console.log(`Standart Sapma: ${stdDev.toFixed(4)}`);
console.log(`Hesaplama süresi: ${elapsed.toFixed(2)}ms`);
}
run();
www/webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
],
experiments: {
asyncWebAssembly: true,
},
devServer: {
port: 8080,
hot: true,
},
mode: 'development'
};
www/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Rust WASM Demo</title>
</head>
<body>
<h1>Rust WebAssembly</h1>
<p>Konsolu aç ve sonuçları gör.</p>
</body>
</html>
Geliştirme sunucusunu başlat:
cd www
npx webpack serve
localhost:8080 adresine git, tarayıcı konsolunu aç. Sonuçları görmelisin.
Test Yazımı
WASM testleri biraz farklı çalışır. wasm-bindgen-test crate’i devreye girer ve testleri gerçek bir tarayıcıda ya da headless Chrome/Firefox’ta çalıştırır.
tests/web.rs dosyasını güncelle:
use wasm_bindgen_test::*;
use my_wasm_project::{fibonacci, calculate_mean, calculate_std_dev};
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn test_fibonacci() {
assert_eq!(fibonacci(0), 0);
assert_eq!(fibonacci(1), 1);
assert_eq!(fibonacci(10), 55);
assert_eq!(fibonacci(20), 6765);
}
#[wasm_bindgen_test]
fn test_calculate_mean() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let mean = calculate_mean(&data);
assert!((mean - 3.0).abs() < 1e-10);
}
#[wasm_bindgen_test]
fn test_empty_array() {
let data: Vec<f64> = vec![];
assert_eq!(calculate_mean(&data), 0.0);
assert_eq!(calculate_std_dev(&data), 0.0);
}
Testleri çalıştırmak için headless Chrome lazım. Önce yükle:
# Ubuntu
sudo apt install -y chromium-browser
# Fedora
sudo dnf install -y chromium
Sonra testleri çalıştır:
wasm-pack test --headless --chrome
Geliştirme İş Akışını Hızlandırmak
Her değişiklikte manuel olarak wasm-pack build çalıştırmak yorucu. cargo-watch ile otomatikleştirelim:
cargo install cargo-watch
WASM build’ini izle ve otomatik yeniden derle:
cargo watch -i pkg -i www -s "wasm-pack build --target bundler --dev"
-i pkg ve -i www parametreleri bu dizinlerdeki değişiklikleri yok say demek, sonsuz döngüye girmemek için önemli.
Paralel olarak bir terminal daha aç ve webpack dev server’ı çalıştır. Rust kodunda değişiklik yaptığında WASM otomatik yeniden derlenir, webpack HMR sayesinde tarayıcı güncellenir.
Boyut Optimizasyonu: Prodüksiyon için Hazırlık
Release derlemesi ile dev derlemesi arasındaki fark ciddi. Bir bak:
# Dev build
wasm-pack build --dev
ls -lh pkg/*.wasm
# Release build
wasm-pack build --release
ls -lh pkg/*.wasm
Farkı görünce şaşırabilirsin, release build çoğu zaman 10 kat küçük çıkabilir.
Daha da küçültmek istiyorsan wasm-opt aracını kullan. Bu araç binaryen paketinin bir parçası:
# Ubuntu
sudo apt install binaryen
# Fedora
sudo dnf install binaryen
# En agresif optimizasyon (-O3 veya -Oz boyut için)
wasm-opt -Oz pkg/my_wasm_project_bg.wasm -o pkg/my_wasm_project_bg_opt.wasm
Boyut farkını karşılaştır:
ls -lh pkg/*.wasm
Cloudflare Workers gibi platformlarda script başına boyut limitleri var (1MB script + 1MB WASM). Bu nedenle WASM boyutu gerçekten önemli.
Makefile ile Her Şeyi Bir Araya Getirmek
Tüm komutları hatırlamak zorunda kalmamak için proje kökünde bir Makefile oluştur:
.PHONY: build build-dev test serve clean fmt lint
build:
wasm-pack build --release --target bundler
wasm-opt -Oz pkg/my_wasm_project_bg.wasm -o pkg/my_wasm_project_bg.wasm
build-dev:
wasm-pack build --dev --target bundler
test:
wasm-pack test --headless --chrome
cargo test
serve: build-dev
cd www && npx webpack serve
clean:
cargo clean
rm -rf pkg www/dist
fmt:
cargo fmt
lint:
cargo clippy -- -D warnings
Artık make build, make test, make serve yeterli.
Yaygın Sorunlar ve Çözümleri
Geliştirme sırasında karşılaşacağın birkaç tipik sorun var.
“error[E0463]: can’t find crate for std“ hatası alıyorsan WASM hedefi eksiktir:
rustup target add wasm32-unknown-unknown
“already exists at… version mismatch” hatası wasm-bindgen versiyon uyumsuzluğunu gösterir. Cargo.toml ve wasm-bindgen-cli versiyonlarını eşitle:
cargo install wasm-bindgen-cli --version $(grep 'wasm-bindgen' Cargo.lock | head -1 | grep -oP 'd+.d+.d+')
WASM modülü yüklenmiyor, “CompileError: AsyncCompile” hatası görüyorsan webpack config’inde experiments.asyncWebAssembly: true olduğundan emin ol.
Panic mesajları tarayıcıda anlamsız görünüyorsa console_error_panic_hook crate’ini etkinleştir. Şablon projede zaten var ama lib.rs başında çağrılması gerekiyor:
#[wasm_bindgen(start)]
pub fn main() {
console_error_panic_hook::set_once();
}
Bu şekilde Rust panic’leri tarayıcı konsoluna okunabilir hata mesajı olarak düşer.
Sonuç
Bu noktada elimizde tam anlamıyla çalışan bir Rust/WASM geliştirme ortamı var. rustup ile versiyonlanmış toolchain, wasm-pack ile otomatik JavaScript entegrasyonu, cargo-watch ile hot-reload, wasm-opt ile prodüksiyon boyut optimizasyonu ve Makefile ile tek komutla her şey.
Buradan sonra gidebileceğin birkaç yön var. Cloudflare Workers veya Fastly Compute@Edge üzerinde bu WASM modüllerini nasıl deploy edeceğini öğrenmek bir sonraki mantıklı adım. Ya da web-sys ve js-sys crate’lerini kullanarak doğrudan DOM manipülasyonu yapmak. Yaxud wasm-streams ile streaming veri işleme.
Rust + WASM kombinasyonu, performans kritik edge senaryolarında JavaScript’in yapamayacaklarını yapabiliyor. Toolchain biraz öğrenme eğrisi gerektiriyor ama bu yazıdaki altyapıyı bir kez kurdum mu, gerisi akıyor. Başka bir WASM konusu için sorularınız varsa yorumlarda buluşuruz.
