Ders 05 / 14
Paket Kaydı ve Bağımlılıklar
Bildirim dosyasının alanları, çıplak belirtecin dizin ağacında aranması, dışa aktarım haritasıyla kapsülleme, bağımlılık türleri ve kilit dosyasının işlevi.
İçindekiler
Modül sistemleri konusundaki tüm belirteçler göreli dosya yollarıydı. Gerçek projelerde
içe aktarımların çoğu bicim-yardimcisi gibi çıplak adlardır: ne uzantı taşırlar ne de
dizin bilgisi.
Bu ad ile dosya arasındaki bağı kuran şey, dosya sistemindeki bir kural ve paketin kendi bildirimidir. Ders, önce paketin ne olduğunu tanımlar, sonra çıplak adın nasıl arandığını adım adım izler.
Bildirim Dosyası
Bir paket (package), kendi bildirimini taşıyan bir dizindir. Bildirim dosyası (manifest) paketin kimliğini, giriş noktalarını ve bağımlılıklarını tanımlar. Linux’a Giriş kursundaki paket yöneticisi kavramı dersinde tanıtılan üstverinin dil düzeyindeki karşılığıdır; alanların işlevi de benzerdir.
Ölçüm kütüphanesinin bildirimi — proje kökündeki package.json:
{ "name": "metin-olcer", "version": "0.1.0", "type": "module", "exports": { ".": "./src/index.mjs", "./bolumleme": "./src/bolumleme.mjs" }, "files": ["src"], "dependencies": { "bicim-yardimcisi": "^1.4.0" } }
Alanların taşıdığı kararlar:
| Alan | Kararı |
|---|---|
name |
Paketin kayıt içindeki benzersiz kimliği |
version |
Bu yayının sürümü; kimliğin ikinci parçası |
type |
Uzantısı .js olan dosyaların hangi modül sistemine göre okunacağı |
exports |
Dışarıdan hangi yolların içe aktarılabileceği |
files |
Yayımlanan arşive hangi dosyaların gireceği |
dependencies |
Çalışması için gereken paketler ve kabul edilen sürüm aralıkları |
Son üç alan tasarım kararıdır, teknik zorunluluk değildir. Hangi dosyanın dışarıdan görüleceğine, hangisinin yayımlanacağına ve hangi sürümlerin kabul edileceğine paketin yazarı karar verir.
Bağımlılık Eklemek
Ölçüm kütüphanesi, ortalama uzunluğu sabit basamakla yazdırmak için küçük bir yardımcıya
bağlanır. Yardımcı paket, kendi bildirimini taşıyan bir dizindir —
node_modules/bicim-yardimcisi/package.json:
{ "name": "bicim-yardimcisi", "version": "1.4.0", "type": "module", "main": "index.mjs" }
// dosya: node_modules/bicim-yardimcisi/index.mjs export function ondalik(sayi, basamak = 2) { return sayi.toFixed(basamak); }
Kütüphaneye eklenen rapor modülü bu paketi çıplak adıyla içe aktarır. Aşağıdaki
dosyanın içe aktardığı src/index.mjs ve onun kullandığı src/bolumleme.mjs ile
src/istatistik.mjs, bu konudaki ES Modülleri dersinde yazılmıştı; ölçüm kütüphanesi
aynı ağaç üzerinde büyümeye devam ediyor:
// dosya: src/rapor.mjs — src/index.mjs, ölçüm işlevini dışa aktaran giriş noktasıdır import { ondalik } from 'bicim-yardimcisi'; import { olc } from './index.mjs'; export function rapor(metin) { const olcum = olc(metin); return `${olcum.sozcukSayisi} sözcük, ortalama ${ondalik(olcum.ortalamaUzunluk)} karakter`; }
// dosya: dene.mjs import { rapor } from './src/rapor.mjs'; console.log(rapor('Modul kendi kapsamini tasir. Betik genel kapsamda calisir.')); console.log(import.meta.resolve('bicim-yardimcisi').split('/node_modules/')[1]);
$ node dene.mjs 8 sözcük, ortalama 6.13 karakter bicim-yardimcisi/index.mjs
Burada iki ayrı olgu vardır ve birbirini gerektirmez: paketin bildirimde yazılı olması ve paketin dizinde bulunması. Bildirimde yazılı olup dizinde bulunmayan bir paket çözümleme hatası verir:
// dosya: eksik-paket.mjs import { ondalik } from 'olmayan-paket'; console.log(ondalik(1.5));
$ node eksik-paket.mjs 2>&1 | grep '^Error' | sed "s|$(pwd -P)/||g" Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'olmayan-paket' imported from eksik-paket.mjs
Ters durum daha sinsidir: dizinde bulunup bildirimde yazılı olmayan bir paket, yerelde sorunsuz çalışır. Çözümleme yalnızca dosya sistemine bakar, bildirimi denetlemez. Paket başka bir yere kurulduğunda o dosya orada bulunmayabilir ve hata ilk kullanımda ortaya çıkar. Bir bağımlılık kullanılıyorsa bildirimde de yazılı olmalıdır; bu kural, sonraki derslerde ele alınacak ağaç düzenlemelerinin altında yatan varsayımdır.
Çıplak Belirteç Nasıl Çözülür
Çıplak ad bir dosya yolu değildir; aranması gereken bir addır. Kural tek cümleyle
yazılabilir: içe aktarmayı yapan dosyanın dizininden başlanır, her dizinde node_modules
alt dizini içinde bu ada bakılır, bulunamazsa bir üst dizine çıkılır.
Kuralı doğrudan uygulayan bir betik, aramanın gerçekten böyle yürüdüğünü gösterir:
// dosya: src/derin/arama.mjs import { dirname, join } from 'node:path'; import { existsSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; // Çıplak belirtecin arandığı dizinler: bulunulan dizinden köke doğru. let dizin = dirname(fileURLToPath(import.meta.url)); while (true) { const aday = join(dizin, 'node_modules', 'bicim-yardimcisi'); console.log(`${existsSync(aday) ? 'BULUNDU ' : 'yok '} ${aday}`); if (existsSync(aday) || dizin === '/') break; dizin = dirname(dizin); } console.log('çalışma zamanının çözdüğü:', import.meta.resolve('bicim-yardimcisi'));
$ node src/derin/arama.mjs | sed "s|$(pwd -P)|.|" yok ./src/derin/node_modules/bicim-yardimcisi yok ./src/node_modules/bicim-yardimcisi BULUNDU ./node_modules/bicim-yardimcisi çalışma zamanının çözdüğü: file://./node_modules/bicim-yardimcisi/index.mjs
sed çağrısı çıktıdaki mutlak yolu kısaltır; son satırdaki adres, o kısaltmanın adres
biçimine uygulanmış hâlidir. Aramanın kendisi dört özelliği açığa çıkarır:
Konuma bağlıdır. Aynı ad, farklı dizinlerdeki iki dosya için farklı pakete çözülebilir. Bu, sonraki derslerde ele alınacak sürüm çakışması çözümünün temelidir.
Kayıt gerektirmez. Çözümleme tümüyle yereldir; ağa çıkılmaz. Ağ, paketler dizine yerleştirilirken kullanılır, çözümleme sırasında değil.
Paketin kendisi konuşur. Dizin bulunduktan sonra hangi dosyanın yükleneceğini paketin bildirimi söyler.
Belirlenimcidir. Aynı dosya ağacında aynı belirteç her zaman aynı dosyaya çözülür. Modül sistemlerinin ilk dersinde sayılan üçüncü güvence budur.
Dışa Aktarım Haritası
Paket dizini bulunduğunda, dışarıdan hangi yolların erişilebilir olduğunu bildirimdeki harita belirler. Haritada listelenmeyen bir yol, dizinde bulunsa bile içe aktarılamaz.
Aşağıdaki iki dosya, metin-olcer paketini kuran ayrı bir tüketici projededir ve o
projenin dizininde çalıştırılır. Tüketicinin kendi bildirimi — tuketici/package.json:
{ "name": "tuketici", "version": "1.0.0", "type": "module", "dependencies": { "metin-olcer": "^0.1.0" } }
// dosya: tuketici/kullan.mjs import { olc } from 'metin-olcer'; import { sozcuklereBol } from 'metin-olcer/bolumleme'; console.log(olc('Bir cumle. Iki cumle.').sozcukSayisi); console.log(sozcuklereBol('bir iki uc').length);
$ node kullan.mjs 4 3
// dosya: tuketici/derin.mjs — haritada olmayan bir iç dosyaya erişmeye çalışır import { ortalamaUzunluk } from 'metin-olcer/src/istatistik.mjs'; console.log(ortalamaUzunluk(['bir', 'iki']));
$ node derin.mjs 2>&1 | grep -E '^Error' | sed "s|$(pwd -P)/||g" Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './src/istatistik.mjs' is not defined by "exports" in node_modules/metin-olcer/package.json imported from derin.mjs
Bu, paket düzeyinde kapsüllemedir. Haritası olmayan bir pakette her iç dosya dışarıya açıktır; tüketiciler iç dosyalara bağlanır ve dosyaların yeniden düzenlenmesi kırıcı değişikliğe dönüşür. Harita, kütüphanenin hangi yollarının sözleşme olduğunu ve hangi dosyalarının serbestçe değiştirilebileceğini ayırır.
Bağımlılık Türleri
Bildirimde bağımlılıklar tek bir liste değildir; her liste farklı bir soruya yanıt verir.
Çalışma bağımlılıkları. Paket çalışırken gereken paketler. Paketi kuran herkes bunları da kurar.
Geliştirme bağımlılıkları. Yalnızca paketi geliştirirken gerekenler: test koşucusu, çözümleyici, derleme aracı. Paketi kullanan taraf bunları kurmaz. Ayrımın anlamı, tüketicinin indirdiği ağacın küçük kalmasıdır.
Eş bağımlılıklar. Paketin çalışması için gereken, ancak paketin kendisinin kurmaması gereken bağımlılıklar. Bir eklenti, genişlettiği kütüphanenin aynı örneğini kullanmak zorundaysa bu listeye yazılır; böylece kütüphaneyi kuran taraf uygulamanın kendisi olur ve ağaçta tek kopya bulunur. Yinelenen kopyanın neden sorun olduğu, bağımlılık ağacı dersinde gösterilecektir.
İsteğe bağlı bağımlılıklar. Kurulumu başarısız olsa da işlemi durdurmayan bağımlılıklar. Paket, eksikliğe karşı yedek bir yol taşımak zorundadır; taşımıyorsa bu liste yanlış kullanılmıştır.
Paket Kaydı ve Kilit Dosyası
Paket kaydı (package registry), ad ve sürüm çiftini bir arşive eşleyen bir dizindir. Yayımlanmış bir ad–sürüm çiftinin içeriği değiştirilemez kabul edilir: aynı çift her zaman aynı baytları vermelidir. Bu değişmezlik, sonraki tüm güvencelerin dayanağıdır.
Bildirimdeki ^1.4.0 gibi bir aralık, tek bir sürümü değil bir kümeyi gösterir. Kurulum
zamanı geldiğinde kümeden bir seçim yapılır. İki farklı zamanda yapılan iki kurulum, küme
büyüdüğü için farklı seçimler yapabilir; sonuç, aynı kaynaktan farklı çalışan iki ağaçtır.
Kilit dosyası (lock file) bu belirsizliği ortadan kaldırır. Kaydettiği üç bilgi vardır:
- Seçilen kesin sürüm. Aralık değil, tek bir sürüm numarası.
- Kaynak adresi. Arşivin nereden alındığı.
- Bütünlük özeti (integrity digest). Arşivin içeriğinin sağlaması.
Ayrıca ağacın biçimi — hangi paketin hangi düzeyde durduğu — kaydedilir. Kilit dosyası bulunduğunda kurulum bir arama değil, bir yeniden üretimdir: yazılı ağaç aynen kurulur.
Bu ayrım, Linux’a Giriş kursundaki bağımlılık çözümlemesinin kısıt problemi olarak tanımlanmasıyla aynı yerden gelir. Çözümleyicinin ürettiği çözüm, o çözümü yeniden hesaplamadan saklanabilir olmalıdır; kilit dosyası bunun kaydıdır. Bu nedenle sürüm denetimine eklenir: bir depoyu klonlayan ikinci geliştiricinin ve yapı sunucusunun aynı ağacı kurması buna bağlıdır.
Özet
- Paket, bildirim dosyası taşıyan bir dizindir; bildirim kimliği, giriş noktalarını, yayımlanacak dosyaları ve bağımlılıkları tanımlar.
- Çıplak belirteç, içe aktaran dosyanın dizininden köke doğru her düzeydeki
node_modulesdizininde aranır; çözümleme yereldir, konuma bağlıdır ve belirlenimcidir. - Dışa aktarım haritası paket düzeyinde kapsülleme sağlar; haritada olmayan iç dosyalar dışarıdan içe aktarılamaz.
- Bağımlılık listeleri farklı sorulara yanıt verir: çalışma, geliştirme, eş ve isteğe bağlı.
- Sürüm aralığı bir küme belirtir; kilit dosyası kümeden yapılan seçimi, kaynağı ve bütünlük özetini kaydederek kurulumu yeniden üretilebilir kılar.
Sonraki Adım
Aralıkların bir küme belirttiği söylendi, ama kümenin sınırlarını neyin çizdiği
söylenmedi. ^1.4.0 yazan bir bildirimin 1.9.0 sürümünü kabul edip 2.0.0 sürümünü
reddetmesinin arkasında, sürüm numarasının parçalarına anlam yükleyen bir sözleşme vardır.
Sonraki ders bu sözleşmeyi ve karşılaştırma kurallarını çalışan kodla kurar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.