Software Development
NPM vs. YARN vs. PNPM
February 24, 2020Bugünkü yazımda, 2020‘nin ilk çeyreğinin sonlarına doğru yaklaşırken, npm, YARN ve Pnpm’in ne olduklarını, çalışma mantıklarını ve farklarını inceliyor olacağız.
NPM, PNPM ve YARN nedir?
npm, Pnpm ve Yarn’ın üçü de Paket Yöneticisi’dir. Peki nedir bu Paket Yöneticisi? Ne iş yapar? Geliştiriciler tarafından araç paylaşmak, çeşitli modüller yüklemek ve bu modüllerin bağımlılıklarını yönetmek için yaygın biçimde kullanılan bir araçtır.
Modüller ve bağımlılıklar;
- Otomatik ya da manuel olarak projelere eklenir
- Eklenen projeden silinir
- Belirli bir dosyada kayıt altında tutulur
- Versiyonları kontrol edilerek güncellenir
Genel olarak üçü de komut satırı aracılığıyla yönetilir.
NPM
Başlıkta NPM yazmak zorunda kalsam da, Node Package Manager’in camelCase kısaltması olarak tamamen javaScript ile yazıldığı için npm şeklinde tanınan, yazılımların / modüllerin / paketlerin yönetilmesini sağlayan, Node.js’in standart olarak kabul ettiği bir paket yöneticisidir.
npm’i kullanabilmek için, öncelikle sisteminizde muhakak Node.js yüklü olmalı. Sisteminizde Node.js ve npm’in olmadığını kontrol edebilmek için de aşağıdaki komutları çalıştırabilirsiniz.
node -v
npm -v
Eğer bu komutlar cevap olarak birer versiyon dönerse, sistemizde bu araçlar mevcut demektir.
Package.json
Yer aldığı projede kullanılan paketler / modüller ve bağımlılıklar (dependencies) hakkında bilgiler içeren bir yerel paket veritabanıdır. Bir projeye başlandığında kendiniz oluşturabileceğiniz gibi (belirli bir syntax ile), npm kullanarak init komutuyla da oluşturulabilir. npm init ile yapılan kurulumlarda araç size bir takım sorular soracak ve dosyayı ona göre oluşturacak. Eğer React Native CLI gibi bir boilerplate ile yeni bir proje başlatacaksanız, CLI’ın init işlemi sonucunda da CLI’da hazırlanan şekilde package.json oluşacaktır.
Paket Kurulumları
— Global Kurulum, modülleri {prefix}/lib/node_modules, yürütme dosyalarını (executable files) {prefix}/bin, man dosyalarını {prefix}/share/man içerisine aktarır. {prefix} genellikle /usr/local dizinine karşılık gelir.
npm install express -g
Kurulum /usr/local/lib/node_modules/express yoluna sahiptir. Global kurulumu — save-dev ile ele aldığımızda ilgili tanımlama da dependencies olarak package.json dosyasına eklenecektir.
— Lokal Kurulum, modülleri çalışılan dizine (proje dizinine) kurar. Genellikle kurulum .node_modules klasörü oluşturularak gerçekleştirilir. Yürütme dosyaları da yine bu klasör içerisinde ./node_modules/.bin/ içeriğinde tutulur. man dosyaları lokal kurulumda işleme alınmaz.
mkdir newproject
cd newproject
npm init -y
npm install express
Komutun uygulanmasının ardından newproject dizininde node_modules klasörü oluşturulacak ve express paketi bu klasör içerisine yüklenecektir. Bu kurulumun ardından uygulamamız içerisinden pakete ../node_modules/express ile erişebiliriz.
Bağımlılıklar (Dependencies)
Bağımlılıklar, kurulum sırasında install komutu le birlikte — save flag’i tanımlandığında, paket bilgilerinin ekleneceği alandır. Bu paketler production için gereklidir. devDependencies ise — save-dev ile paketlerin detaylarının ekleneceği yerdir. Burada tutulan paketler geliştirme ve test için gereklidir.
YARN
Yarn, Facebook yazılım ekiplerinin öncülüğünde Google, Exponent ve Tilde şirketlerinin de destekleriyle birlikte npm’e alternatif olarak geliştirilen bir paket yöneticisidir.
Genel olarak npm’in özelliklerini desteklemesiyle birlikte, Facebook mühendislerinin başını ağrıtan güvenlik, tutarlılık ve performans problemlerini çözmek amacıyla yeni özellikler de getirmiştir.
Yarn, yüklenen her paketi önbelleğe alan, böylelikle paketin tekrar yüklenmesine gerek kalmayan, kaynak kullanımını en üst düzeye çıkarmak için gerçekleştirilen işlemleri paralelleştiren bir yapıya sahiptir.
Yarn kurulumu için sistem seviyesinde bir başka paket yöneticisi kullanabiliriz. macOS için Brew veya MacPorts tercih edilebilir.
brew install yarn
#ya da
sudo port install yarn
Elbette paket yöneticisi olmaksızın da yükleme işlemi gerçekleştirilebilir. Komut satırı üzerinden curl aracılığıyla indirmek işlemi gerçekleştirmek için şu komut kullanılabilir.
curl -o- -L https://yarnpkg.com/install.sh | bash
Diğer indirme ve versiyon kullanım seçenekleri için Yarn > Installation sayfasını inceleyebilirsiniz
Yarn ile yeni bir proje oluşturmak için yarn init komutunu kullanırız. Projenin yürütüleceği dizinde bu komutu uyguladığımızda bizden prompt aracılığıyla name, version, entry point, repository url gibi bazı bilgiler istenir. Bilgilerin girilmesi ya da es geçilmesinin ardından bir package.json dosyası oluşturulur.
Paket Kurulumları
— Yükleme işlemini global olarak gerçekleştirmek için global parametresini eklemek yeterli.
yarn add global [paket-adi]
— Proje dizinine yeni bir paket / bağımlılık (dependency) eklemek istediğimizde de yarn add komutundan faydalanırız.
yarn add [paket-adi]
yarn add [paket-adi]@[paket-versiyonu]
yarn add [paket-adi]@[etiket]
— Yarn özelliklerine değindiğim paragrafta paralelleştirmeden bahsetmiştim.
yarn add [paket-adi-1] [paket-adi-2] [paket-adi-3] [paket-adi-4]
PNPM
pnpm, performant npm’in kısaltması olan, npm ile Yarn’ın tüm özelliklerine sahip ve birçok açıdan daha iyi performans gösteren bir paket yöneticisidir.
Hem npm hem de Yarn’dan çok daha hızlı olduğu iddia edilmektedir. Benchmark kıyaslamalarına buradan ulaşabilirsiniz.
Sabit bağlantıları kullanarak sistemdeki Node Modülleri tekilleştirir, ardından her bir projenin node_modules klasörü içinde sembolik linkler(symlinks) kullanır; yani artık sisteminizde örneğin lodash’ın tek bir kopyası olacak 🎉. Bu da diskinizde müthiş bir alan kazanımı demek.
Yarn da geçmişte sembolik bağlantıları kullanmayı düşündü, ancak birkaç nedenden ötürü başka bir karar vererek yollarını değiştirdiler. Bireysel denemelerde pnpm’in performasını oldukça başarılı buldum ve herhangi bir sorun yaşatmadı.
Komutları Yarn ile çok benzer olduğu için hiçbir alışma problemi de olmadı.
Kullanımı ile ilgili tüm detaylar için linkini kullanabilirsiniz.
Bu linkte açıklanan bir “strictess” özelliğine sahiptir. Bu özellik, package.json’da olmayan herhangi bir modülü kullanmanızı engeller. Bu, izlemesi zor hatalardan kaçınmanızı sağlayan harika bir özellik olarak dikkat çekiyor.
npm install -g pnpm
pnpm, bir drop-in replacement olduğu için, npm için geçerli olan tüm komutları pnpm için de kullanabilirsiniz.
FARKLAR
Hız — Performans
- npm aracı Node paketlerini merkezi repodan sıralı olarak indirirken, YARN eş zamanlı olarak birden fazla paketi indirebilir. Böylece daha hızlı yüklemelere kapı aralar. YARN ayrıca yarnpkg.com adında bir uzak depoya da sahiptir.
- YARN aracı ile yüklenen a.b.c sürümündeki bir paket, lokal bilgisayarınızda ayrıca depolanır. Böylece ilgili sürümdeki paket tekrar indirilmeye çalışıldığında uzak repoya uğraması gerekmez.
- pnpm, global store’dan projenin node_modules klasörlerine sabit bağlantılar oluşturur. Sabit bağlantılar, disk üzerinde orijinal dosyaların bulunduğu yeri gösterir. Örneğin, projenizde bir bağımlılık olarak foo varsa ve 1MB alan kaplıyorsa, projenin node_modules klasöründe 1MB alan ve global mağazadaki aynı miktarda alan kaplıyor gibi görünecektir. Ancak bu 1MB, diskte iki farklı konumdan adreslenen alanla aynıdır. Yani toplam foo 2MB değil, 1MB kaplar. Aynı paketler için her zaman yeni symlink oluşturulduğu için, hem hız hem de disk alanı açısından yarar sağlar
npm, pnpm veya Yarn, bir paket kurması gerektiğinde, bir dizi görevi yerine getirir. npm ve pnpm’de bu görevler paket başına ve sırayla yürütülür, yani bir paketten diğerine geçmeden önce tam olarak yüklenmesini bekler. Yarn ise bu görevleri paralel olarak gerçekleştirerek performansı artırır.
Tutarlılık
Node modül sisteminde her paketin bir versiyonu bulunmaktaydı. Versiyonlama biçiminde semantik versiyonlama usülü tercih edilmekteydi. Bilindiği üzere modül bağımlılıkları isim ve sürüm aralığı olarak package.json isimli dosyada tutulmaktaydı.
Örneğin, aşağıdaki amodule, lemodule modülünün sürüm olarak 1.0.0 ve yukarısı ve 1.0.7 ve aşağısına bağımlıymış. Onsuz yapamazmış.
{
“name”: “amodule”,
…
“dependencies”: {
“lemodule”: “>=1.0.0 <=1.0.7”
}
…
}
Fakat bu şekilde belirtilen sürüm aralıkları olası tutarsızlıklara açıktı. Örneğin sizin makinenizde 1.0.2 sürümü yüklüyken, arkadaşınızın makinesinde 1.0.4 sürümü yüklü olabilir. 1.0.2 de bulunabilecek bir olası bug tüm düzeni etkileyebiliyordu. Bunun bir de canlı ortamda karşınıza çıktığını bir düşünün!
YARN ise bambaşka bir bakış açısıyla yarn.lock adında özel bir dosya kullanmaya başlamıştı. Eğer projenizde yarn.lock bulunmuyorsa, YARN tarafından oluşturulmamakta ve güncellenmektedir. yarn.lock içinde, tam versiyon, paketin nereden indirildiği ve veri bütünlüğünün kontrol edilmesi için checksum bilgisi gibi bilgiler bulundurulur. Bu sayede aynı proje kullanıcılarının t anında aynı modül ağacıyla çalışması sağlanmış olur. Paketler ayrıca checksum bilgileri üzerinden kontrol edildiğinden gözler arkada kalmaz.
Bu yenilik çok cazipti ve geliştiricilerin endişelenmesi gereken bir şey değildi. Bununla birlikte, NPM v5.0.0’dan itibaren, NPM otomatik olarak aynı şeyi yapan kendi kilit dosyasını oluşturmaya başladı. Bu dosyanın ismi de Package-lock.json oldu.
Yarn’ın daha önce geliştirdiği bu yapı, npm’in da aynı çalışma mantığına dönmesi ile birlikte çok büyük fark yaratan bir avantaj olma özelliğini yitirmiş oldu.
Çıktı Detayları
Varsayılan olarak npm çok ayrıntılıdır. Örneğin, npm install <package> çalıştırıldığında tüm kurulu paketleri recursive olarak listeler. Öte yandan Yarn hiç de ayrıntılı değildir. Ayrıntılar diğer komutlar aracılığıyla alınabilir ama varsayılan olarak uygun emojilerle (Windows’ta değilseniz) çok daha az özet, ihtiyaç olan bilgileri listeler.
Güvenlik
Facebook’un Yarn’ı geliştirmesinin ana nedenlerinden biri, npm’in güvenlik konularını daha iyi ele almaktı. npm’de, paketlerin henüz daha kurulum sırasında otomatik olarak ve anında, hatta bağımlılıklarından otomatik olarak ve anında kod çalıştırmasına izin verilir. Bu özelliğin kolaylıkları olsa da, özellikle daha önce bahsettiğim production paketi oluşturma sürecinde oluşabilecek açıkları göz önünde bulundurarak birkaç güvenlik endişesi ortaya çıkarıyor. Tersine, Yarn yalnızca yarn.lock veya package.json dosyalarınızdan yüklenir. Daha spesifik olarak yarn.lock, aynı paketin tüm cihazlara yüklenmesini sağlar, böylece hataların farklı sürümlerin kurulma şansını büyük ölçüde azaltır.
Bu kaygılar yazım aşamasında hala yürürlükte olduğundan, Yarn’ın güvenlik açısından tercih edilebilir olduğunu düşünüyorum.
Komunite Verileri
Sonuç
npm’den alınmış bir fork olmamasına rağmen, Yarn npm’in birçok noktadaki eksiklerini kapattı. Teknolojiye yön veren şirketlerin ihtiyaçları ve sıkıntılarıyla birlikte geliştirilen Yarn, npm’in 5.0 sürümünden sonra bile komünite tarafından daha çok tercih edilmeye ve kullanılmaya devam ediyor. Buradaki tek sorun, Yarn’ın yol haritasının belli olmaması. Pnpm ise aktif olarak fazla proje geliştiren, bilgisayarında birçok farklı projede aynı kütüphaneler bulunan geliştiriciler için fark yaratıyor. Ama yine de kendi geliştirdiğimiz React Native projemizde de yaptığım denemelerde her seferinde yaklaşık %25’lik performans katkısı sunan Yarn, hem hali hazırdaki sorunları çözen öncü yapısı, hem de performans anlamında kattığı verimlilik ile benim de tercihim oluyor.
Peki sizin tercihiniz hangisi?
Kaynaklar:
https://www.kochan.io/nodejs/why-should-we-use-pnpm.html
https://medium.com/pnpm/never-ever-forget-to-install-a-dependency-1c39dd3bbb37
https://github.com/pnpm/benchmarks-of-javascript-package-managers
https://smddzcy.com/posts/2019-05-19/npm-vs-yarn-vs-pnpm-package-manager-comparison
https://flaviocopes.com/pnpm/
https://pnpm.js.org/en/about-package-store
https://iamturns.com/yarn-vs-npm-2018/
https://waverleysoftware.com/blog/yarn-vs-npm/
https://www.keycdn.com/blog/npm-vs-yarn
https://github.com/appleboy/npm-vs-yarn
https://dev.to/urfan/npm-vs-yarn-2a2e
https://ceaksan.com/tr/npm-node-package-manager/
Author: Efecan Tekin