Kurulum Süresi ve Disk Kullanımı: Content-Addressable Store'a Karşı Global Virtual Store
pnpm'in mimarisi baştan beri aynı: her paket sürümü diskte tek bir content-addressable store'da tutulur, projenin node_modules'ü buraya hard link (aynı disk) veya symlink ile bağlanır. Aynı paketi 50 projede kullanıyorsan diskte bir kopya vardır, elli değil — pnpm'in sıcak kurulum avantajı büyük ölçüde buradan gelir. pnpm bunun üstüne v10.12.1'de opt-in bir global virtual store ekledi (enableGlobalVirtualStore; v11.23.0'dan beri kanonik yazımı virtualStoreType: global): açıldığında proje node_modules'ü, makine genelinde paylaşılan tek bir sanal store'a symlink'lenir. Bun tarihsel olarak kendi cache'inden node_modules'e kopyalama yapıyordu; Bun 1.4 bunu değiştirdi ve --linker=isolated + globalStore = true ile kavramsal olarak aynı modele geçti — paketler cache'e bir kez extract edilir, node_modules/.bun/<pkg>@<ver> oraya symlink'lenir. Sana pratik anlamı şu: "paylaşılan store" iki araçta da bir tercih, varsayılan değil. Bun'ın varsayılan --linker=hoisted modunda kalırsan disk avantajını görmezsin; pnpm'de global store'a geçmek ayrı bir karardır. Hangi modu seçersen CI'da da onu sabitle, aksi halde local'de hızlı olan kurulum runner'da farklı davranır.
Lockfile Formatı ve CI Determinizmi
pnpm'in pnpm-lock.yaml'ı yıllardır aynı: insan tarafından incelenebilir YAML, dependency graph'ı ve entegrite hash'lerini tutar. 12.2-12.3'te pnpm bu dosyayı daha akıllıca okumaya başladı — workspace projeleri keşfedilirken lockfile paralel parse ediliyor ve resolver artık dosyanın tamamını kopyalamadan başlıyor, yani büyük monorepo'larda pnpm install başlangıç maliyeti düşüyor. Bun tarafında hikaye daha yakın tarihli: bun.lock metin tabanlı lockfile'ı v1.1.39'da tanıtıldı ve Bun 1.2'de önceki ikili bun.lockb formatının yerini alan varsayılan oldu — artık git diff ile okunabilir, PR review'da lockfile değişikliğini görebilirsin. İki tarafta da determinizm kuralı aynı: CI'da --frozen-lockfile (pnpm) veya bun install --frozen-lockfile kullanmadan build almak, lockfile'ın sessizce güncellenmesine ve "local'de çalışıyordu" sürprizlerine kapı açar. Dikkat etmen gereken şey lockfile'ı repo'ya commit etmek kadar, hangi paket yöneticisinin lockfile'ını .gitignore'a alacağın: pnpm-lock.yaml ve bun.lock aynı repoda aynı anda var olursa hangisinin doğruluk kaynağı olduğu belirsizleşir.
Tedarik Zinciri Güvenliği: Trust Bayrakları ve Postinstall Politikası
İki aracın felsefesi burada ayrışıyor. pnpm 10.0.0'dan beri bağımlılıkların lifecycle script'leri koşulmuyor; izin vermek istediğin paketi pnpm-workspace.yaml'daki allowBuilds haritasına esbuild: true gibi eklemelisin (allowBuilds v10.26.0'da geldi; eski ad onlyBuiltDependencies v11'de kaldırıldı). 12.2-12.3 denetimi genişletti: pnpm remove ve pnpm update artık --trust-lockfile, --trust-policy, --trust-policy-exclude ve --trust-policy-ignore-after bayraklarını da alıyor; pnpm remove ise lockfile'ın TAMAMINI aktif politikalara karşı yeniden doğruluyor. Bun aynı hedefe başka yoldan gidiyor: bun install postinstall script'lerini varsayılan bloklar, yalnızca trustedDependencies allowlist'indeki paketler script koşturabilir; bloklananları bun pm untrusted ile görür, bun pm trust ile işaretlersin. Bun'da bir kontrol daha var: bunfig.toml [install] altında minimumReleaseAge, verilen saniye eşiğinden yeni yayımlanmış npm sürümlerini eliyor (varsayılan null, kapalı); minimumReleaseAgeExcludes paketleri muaf tutuyor. Pratik fark: pnpm politikayı lockfile'ı değiştiren her komutta zorunlu kılıyor, Bun'ın modeli kurulum anına ve sürüm yaşına odaklı.
Monorepo/Workspace Desteği ve Filtreleme
pnpm workspaces uzun süredir monorepo'nun referans noktalarından biri: pnpm-workspace.yaml ile proje desenleri tanımlanır, --filter ile paket adı/dizin/değişiklik-bazlı seçim yapılır, catalog: alanı ortak bağımlılık sürümlerini merkezi bir yerden yönetir. 12.2-12.3'te workspace desenleri artık eşzamanlı probe ediliyor ve bulunan package.json dosyaları paralel okunuyor — literal dizinler ve sondaki * içeren desenler için kısayol var, dependency graph çalışma başına bir kez kuruluyor (öncesinde iki kez kuruluyordu). Aynı sürümde catalog'lar workspace: protokolünü öğrendi, yani bir catalog girdisi artık workspace içi bir paketi işaret edebiliyor. Bun workspaces da native: kök package.json'da workspaces alanı tanımlanır, bun install --filter <desen> ile belirli workspace'lere kurulum sınırlanır. Fark, etraflarındaki araç ekosisteminde: pnpm workspace'leri Turborepo, Nx, Changesets gibi araçlarla yıllardır olgunlaşmış entegrasyonlara sahip; Bun'ın workspace deneyimi hızlı ve batteries-included ama görev çalıştırma (task running) tarafı bu araçlar kadar zengin değil — çoğu ekip Bun'ı kurulum motoru, Turborepo/Nx'i orkestrasyon katmanı olarak birlikte kullanıyor.
Peer-Dependency Katılığı ve Phantom Dependency Koruması
pnpm'in imzası burada: node_modules yapısı simetrik değil, iç içe symlink hiyerarşisiyle her paket yalnızca package.json'da bildirdiği bağımlılıklara erişebiliyor. Bir paket, kendi dependencies'inde olmayan ama flat node_modules'te "tesadüfen" erişilebilen bir alt-bağımlılığı (phantom dependency) import edemiyor — pnpm bunu kurulum zamanında mimari olarak engelliyor, ekstra bayrak gerekmiyor. Bun'ın klasik --linker=hoisted modu npm/Yarn'a benzer düz bir node_modules üretiyordu, phantom dependency riski oradaydı; v1.3.2/configVersion ile gelen, 1.4'te global store ile birleşen isolated installs (--linker=isolated) bu riski kapatıyor — resmi dokümantasyon bunu "pnpm'in yaklaşımına benzer sıkı bağımlılık izolasyonu" olarak tanımlıyor. Varsayılanı tarihlendirerek oku: yeni workspace/monorepo projelerinde (lockfile'da configVersion = 1) isolated zaten varsayılan; tek-paket projelerde ve v1.3.2 öncesi açılmış mevcut projelerde (configVersion = 0) varsayılan hoisted kalıyor, izolasyonu --linker bayrağıyla ya da bunfig.toml → [install] linker = "isolated" ile açıkça seçmelisin. pnpm'de bu davranış proje tipinden bağımsız varsayılan; böyle bir ayrım yapmana gerek yok.
CI Önbellekleme, Docker Layer Uyumu ve Offline Kurulum
CI'da kurulum süresi genelde iki şeye bağlı: cache hit oranı ve offline davranışı. İkisinin de açık bayrakları var, üstelik iki araçta da aynı adlarla. Bun tarafında bun install --offline ağa hiç çıkmadan yalnız cache'ten kurar, --prefer-offline ise cache'te varsa onu kullanır, yoksa ağa düşer. pnpm'de aynı ikili birebir mevcut: pnpm install --offline yalnızca store'da hazır olan paketleri kullanır ve bir paket yerelde bulunamazsa kurulum hata verir; --prefer-offline cache'lenmiş veri için tazelik kontrollerini atlar, eksik olanı sunucudan ister. Yani "ağa çıkma" garantisi bir araca özgü değil — asıl ayrım, cache/store'u CI'da nasıl geri yüklediğinde. pnpm'de store diskte kalıcı olduğu için runner'da store dizinini (örn. GitHub Actions'ta actions/cache ile) cache'lemek yaygın pratiktir; konumu pnpm store path ile öğrenip cache anahtarına eklersin. Bun tarafında aynı iş global cache dizini için yapılır. Docker katman uyumunda disiplin ikisinde de aynı: önce yalnız package.json + lockfile'ı kopyala, kurulumu çalıştır, sonra kaynak kodu kopyala — böylece kaynak değişse bile bağımlılık layer'ı cache'ten gelir.
Ekosistem Araç Uyumu: Turborepo, Nx, Changesets
Bir paket yöneticisi seçimi tek başına yaşamıyor — üzerine kurduğun task runner ve sürüm yönetimi araçlarıyla uyumu belirleyici. pnpm workspaces; Turborepo, Nx ve Changesets ile yıllar içinde olgunlaşmış, geniş kullanılan entegrasyonlara sahip — bu üç araç da pnpm workspace'lerini uzun süredir yaygın bir zemin olarak destekliyor. Bun workspaces bu araçlarla da çalışır, ama entegrasyonun olgunluk süresi pnpm'inkinden kısa, dolayısıyla köşe durumlarda (ör. karma bir monorepo'da bazı paketler pnpm bazıları Bun ile kurulmuşsa) daha az test edilmiş bir zeminde olursun. Pratik öneri: hangi paket yöneticisini seçersen seç, task runner'ını (Turborepo veya Nx) ayrı bir karar olarak değerlendir ve ikisini aynı anda değiştirme — bir değişkeni sabit tutmak, performans regresyonunun hangi araçtan geldiğini ayırt etmeni kolaylaştırır.