Modern Paket Yöneticileri

NPM, Yarn ve PNPM ile Bağımlılık Yönetimi

1. Paket Yönetimi Nedir?

Modern yazılım geliştirme sürecinde, tekerleği her seferinde yeniden icat etmek yerine başkaları tarafından yazılmış kütüphaneleri (paketleri) kullanırız. Paket yöneticileri, bu kütüphanelerin projeye dahil edilmesi, güncellenmesi ve silinmesi süreçlerini otomatize eden araçlardır. Bağımlılık (dependency) yönetimi olarak da adlandırılan bu süreç, projenizin hangi dış kaynaklara ihtiyaç duyduğunu takip eder. NPM, Node.js ile birlikte gelen dünyanın en büyük yazılım kayıt defteridir. Paket yöneticileri sadece indirme yapmaz, aynı zamanda versiyon çakışmalarını çözer ve güvenliği denetler. İyi bir paket yönetimi, projenin taşınabilirliğini sağlar; yani aynı package.json dosyasına sahip iki geliştirici, dünyanın farklı yerlerinde aynı çalışma ortamını saniyeler içinde kurabilir.

2. Package.json ve Package-lock.json

Her Node.js projesinin kalbi package.json dosyasıdır. Bu dosya projenin kimlik kartıdır; ismi, versiyonu, scriptleri ve en önemlisi bağımlılıkları burada listelenir. Ancak package.json versiyon aralıklarını (örn: ^1.2.0) belirtirken, package-lock.json (veya yarn.lock) dosyasının görevi çok daha kritiktir. Lock dosyası, o an yüklenen kütüphanelerin tam ve kesin versiyonlarını, hatta indirme kaynaklarını ve bütünlük (hash) kodlarını kaydeder. Bu, "benim bilgisayarımda çalışıyor ama sende çalışmıyor" sorununu ortadan kaldırır. Lock dosyaları asla manuel olarak düzenlenmemeli ve mutlaka Git gibi versiyon kontrol sistemlerine dahil edilmelidir. Eğer lock dosyası olmazsa, iki geliştirici aynı projeyi farklı zamanlarda kurduğunda, kütüphanelerin alt versiyon güncellemeleri nedeniyle farklı sonuçlar alabilir.

3. NPM (Node Package Manager)

NPM, JavaScript ekosisteminin varsayılan ve en yaygın paket yöneticisidir. 2010 yılında piyasaya sürülmüş olup, bugün milyarlarca indirmeye ev sahipliği yapmaktadır. NPM'in temel komutları (install, update, publish) her geliştiricinin bilmesi gereken araçlardır. NPM v5'ten sonra gelen hız optimizasyonları ve lock dosyası desteğiyle modern standartlara ulaşmıştır. npm audit komutuyla projelerdeki güvenlik açıklarını tarayabilir, npm run ile özel görevleri tetikleyebilirsiniz. NPM'in en büyük avantajı, hiçbir ek kurulum gerektirmeden Node.js ile birlikte gelmesidir. Ancak geniş projelerde node_modules klasörünün aşırı büyümesi ve bazı durumlarda Yarn'a göre daha yavaş kalması gibi dezavantajları toplulukta alternatiflerin doğmasına neden olmuştur.

4. Yarn: Hız ve Güvenliğin Öncüsü

Yarn, 2016 yılında Facebook tarafından NPM'in o zamanki performans ve güvenlik açıklarına bir çözüm olarak geliştirildi. Paketleri paralel indirme yeteneği, daha güvenli checksum doğrulamaları ve o zamanlar NPM'de olmayan lock dosyası özelliğiyle bir anda popüler oldu. Yarn v1 (Classic), paket yönetimini çok daha kararlı hale getirdi. Daha sonra çıkan Yarn v2 (Berry) ise "Plug'n'Play" (PnP) özelliğiyle node_modules klasörünü tamamen ortadan kaldırmayı hedefledi. Yarn, özellikle büyük monorepo projelerinde Workspace desteğiyle çok güçlüdür. Bugün NPM aradaki farkı büyük oranda kapatsa da, Yarn hala deterministik kurulum hızı ve gelişmiş CLI (komut satırı) deneyimiyle birçok profesyonel ekip tarafından tercih edilmeye devam etmektedir.

5. PNPM: Performanslı ve Verimli

PNPM (Performant NPM), son yıllarda özellikle disk alanı ve hız takıntısı olan geliştiricilerin favorisi haline geldi. NPM ve Yarn, her projeye kütüphaneleri tekrar tekrar indirip node_modules içine kopyalarken, PNPM "content-addressable store" sistemini kullanır. Yani bilgisayarınızda bir paketin bir versiyonu bir kez indirilir ve tüm projeler oraya "hard link" ile bağlanır. Bu, disk alanından devasa tasarruf sağlar ve kurulum sürelerini saniyelere indirir. Ayrıca PNPM, "strict" yapısıyla meşhurdur; bir paket sadece package.json içinde belirtilmişse ona erişebilirsiniz (NPM'de dolaylı bağımlılıklara erişim mümkündür ve bu bazen gizli hatalara yol açar). Modern monorepo yapılarında PNPM şu an en çok önerilen araçtır.

6. Semantic Versioning (SemVer)

Paket yönetiminin dilini anlamak için SemVer (Anlamsal Versiyonlama) kurallarını bilmek gerekir. Bir versiyon numarası üç parçadan oluşur: MAJOR.MINOR.PATCH (örn: 2.3.1). MAJOR, geriye dönük uyumsuz büyük değişiklikleri; MINOR, yeni özellikler ama geriye dönük uyumlu güncellemeleri; PATCH ise sadece hata düzeltmelerini temsil eder. package.json içindeki semboller de buna göre çalışır: ^ işareti major versiyon sabit kalmak şartıyla güncellemeleri alır, ~ işareti sadece patch güncellemelerini alır. Eğer hiçbir sembol yoksa, versiyon sabitlenmiş demektir. SemVer kurallarına uymayan paket geliştiricileri, istemeden de olsa binlerce projenin bozulmasına neden olabilir. Geliştiriciler olarak bizler de bağımlılık güncellerken bu kurallara güvenerek hareket ederiz.

7. Bağımlılık Türleri: Dev vs Prod

Projenizde kullandığınız paketler iki ana gruba ayrılır. dependencies, uygulamanın çalışması için canlı ortamda (production) gereken paketlerdir (React, Axios, Express vb.). devDependencies ise sadece geliştirme sürecinde, test yazarken veya kod derlerken kullanılan araçlardır (Jest, ESLint, Webpack vb.). Bu ayrım kritiktir çünkü uygulama canlıya alınırken (deploy) devDependencies klasörleri elenir, böylece sunucuda gereksiz yer kaplanmaz ve güvenlik riski azalır. npm install --save-dev [paket] komutuyla bir paketi geliştirme bağımlılığı olarak kaydedebilirsiniz. Ayrıca bazı durumlarda peerDependencies kullanılır; bu da paketin çalışması için ana projede belirli bir versiyonun (örn: React ^18) zaten yüklü olması gerektiğini belirtir.

8. Güvenlik Denetimi: Audit ve Fix

Paket yöneticileri, projenize giren her kodun güvenliğini denetlemek için yerleşik araçlara sahiptir. Her kurulumdan sonra npm audit raporu, kullanılan kütüphanelerin içinde bilinen bir açık olup olmadığını söyler. Bir kütüphanenin alt bağımlılıklarından biri bile hacklenmişse bu raporda görünür. npm audit fix komutu, uyumlu versiyon güncellemeleriyle bu açıkları otomatik kapatmaya çalışır. Ancak bazı "breaking change" içeren güncellemeler manuel müdahale gerektirir. Paket seçerken sadece popülerliğe değil, kütüphanenin ne sıklıkla güncellendiğine ve bakımının (maintenance) yapılıp yapılmadığına bakmak siber güvenlik için temel kuraldır. Hiç güncellenmeyen bir paket, projenizin en zayıf halkası olabilir.

9. Npx: Kurmadan Çalıştırmak

Bazen bir paketi projeye kalıcı olarak yüklemek yerine sadece bir kez çalıştırmak istersiniz (örn: bir proje iskeleti oluşturmak veya tek seferlik bir script). NPM v5.2 ile gelen npx (Node Package Runner) tam olarak bu işe yarar. npx create-react-app my-app komutunu verdiğinizde, npx o paketin en güncel versiyonunu geçici bir belleğe indirir, çalıştırır ve sonra siler. Bu, bilgisayarınızda global paket kirliliğini önler ve her zaman en güncel araçları kullanmanızı sağlar. Ayrıca npx, projenin node_modules/.bin klasöründeki yerel komutları da kolayca çalıştırmanızı sağlar. Paket yöneticilerinin sunduğu bu tür yardımcı araçlar, iş akışını hızlandıran gizli kahramanlardır.

10. Global ve Local Paket Yönetimi

Paketler iki şekilde kurulabilir: Global veya Yerel. Global kurulumlar (-g flagı ile), bilgisayarın her yerinden erişilebilen komut satırı araçları (nodemon, typescript-compiler vb.) içindir. Yerel kurulumlar ise sadece ilgili projenin klasöründe geçerlidir. Modern dünyada, projelerin bağımlılıkları arasındaki versiyon farklarını yönetmek zor olduğu için "Global" kurulumlardan mümkün olduğunca kaçınılır. Bunun yerine her projeye kendi bağımlılıklarını yerel olarak kurmak ve package.json içindeki scriptler üzerinden çalıştırmak en iyi uygulamadır. Ayrıca farklı Node.js versiyonları arasında geçiş yapmak için NVM (Node Version Manager) kullanmak, paket yöneticilerinin doğru Node ortamında çalışmasını sağlayarak versiyon karmaşasını tamamen bitirir.