Bölüm 18 / 20
ES modülleri
npm ve paketleyici (bundler) kavramı.
14 dakikalık okuma
Buraya kadar yazdığın her şey tek bir kapsamda duruyordu. Gerçek bir uygulama onlarca dosyadan oluşur ve bu dosyaların birbirini düzenli biçimde görmesi gerekir. JavaScript bu yeteneğe uzun süre sahip değildi; bugün ES modülleri ile tarayıcıda yerleşik olarak var. Bu ders modülleri, arkasındaki paket ekosistemini (npm) ve neredeyse her modern ön yüz projesinde bulunan paketleyici kavramını anlatıyor — ayrıca bunların ne zaman gerekmediğini, ki bu sitenin kendisi o kararın örneğidir.
01Ne öğreneceksin
- Modüllerden önce kodun nasıl bölündüğü ve neden sorunluydu
export/import: adlandırılmış ve varsayılan dışa aktarım- Modülün beş özel davranışı ve en sık düşülen üç tuzağı
- Modüllerin tekil (singleton) olması ve bunun tasarıma etkisi
- Dinamik
import()ve kod bölme - ES modülleri ile CommonJS (
require) farkı - npm,
package.json, sürüm aralıkları ve kilit dosyası dependenciesiledevDependenciesayrımı- Bağımlılık riski: geçişli bağımlılıklar ve tedarik zinciri
- Paketleyici ne yapar: ağaç sarsma, kod bölme, küçültme, kaynak eşleme
- Ne zaman derleme adımı gerekmez — bu sitenin kararı
02Modüllerden önce
2015 öncesinde kodu bölmenin tek yolu birden çok <script> etiketiydi ve
bunun üç sorunu vardı:
- Küresel kapsam kirliliği. Her dosyadaki değişkenler
window'a yazılırdı; iki kütüphane aynı adı kullandığında biri diğerini sessizce ezerdi. - Sıra bağımlılığı. Bir dosya diğerini kullanıyorsa HTML'de önce yazılmak zorundaydı; bağımlılık grafiği elle yönetilirdi.
- Gizlilik yok. Bir dosyanın iç yardımcı fonksiyonlarını dışarıdan saklamanın yolu yoktu.
Çözüm 14. derste adı geçen IIFE kalıbıydı: kodu hemen çalışan bir fonksiyonla sarmalayıp yalnız istediğini dışarı vermek.
var Sepet = (function () {
let urunler = []; // dışarıdan ERİŞİLEMEZ (kapanış)
function topla() { … } // özel
return { ekle, topla }; // yalnız bunlar dışarı çıkar
})();
Bu, kapsamı çözüyordu ama bağımlılık sırasını çözmüyordu. ES modülleri ikisini birden çözer.
03ES modülleri: sözdizimi
// ── bicim.js ─────────────────────────────────────────
export const PARA_BIRIMI = "TRY"; // adlandırılmış dışa aktarım
export function tutar(kurus) {
return new Intl.NumberFormat("tr-TR",
{ style: "currency", currency: PARA_BIRIMI }).format(kurus / 100);
}
function ic() { … } // dışa aktarılmadı → GİZLİ
export default class Bicimlendirici { … } // VARSAYILAN — dosya başına en fazla bir tane
// ── uygulama.js ──────────────────────────────────────
import Bicimlendirici, { tutar, PARA_BIRIMI } from "./bicim.js";
import { tutar as paraYaz } from "./bicim.js"; // yeniden adlandırma
import * as bicim from "./bicim.js"; // ad alanı olarak topla
import "./yan-etkiler.js"; // yalnız çalıştır, bir şey alma
export { tutar } from "./bicim.js"; // yeniden dışa aktar (barrel dosyası)
<script type="module" src="uygulama.js"></script>
| Adlandırılmış | Varsayılan | |
|---|---|---|
| Sayı | Sınırsız | Dosya başına bir |
| İçe aktarma | Süslü parantezle, tam adla | Parantezsiz, istediğin adla |
| Yazım hatası | Hata verir — ad bulunamaz | Sessizce farklı ad kullanılır |
| Otomatik tamamlama / yeniden adlandırma | Editör destekler | Daha zayıf |
Bu tablo yüzünden birçok ekip adlandırılmış dışa aktarımı varsayılan yapar: adlar sabit kalır, editör yeniden adlandırmayı tüm projede yapabilir ve yanlış yazım derhal hata verir. Varsayılan dışa aktarımın makul kullanımı, dosyanın tek bir şeyi temsil ettiği durumlardır (bir React bileşeni gibi).
04Modülün beş davranışı
| Davranış | Sonucu |
|---|---|
| Kendi kapsamı vardır | Üst seviye değişkenler window'a yazılmaz |
| Her zaman sıkı moddadır | "use strict" yazmaya gerek yok (13. ders) |
defer gibi yüklenir | Ayrıştırmayı durdurmaz, belge hazır olunca çalışır (1. ders) |
| Bir kez değerlendirilir | Aynı modül on yerden içe aktarılsa da tek örnek vardır |
| İçe aktarımlar kaldırılır | Bağımlılıklar kod çalışmadan önce çözülür — statik analiz mümkün |
Tekil olma davranışı tasarımı doğrudan etkiler: bir modülde tutulan üst seviye değişken, uygulamanın paylaşılan durumu hâline gelir. Bu kimi zaman istenendir (yapılandırma, önbellek), kimi zaman gizli bir bağımlılıktır ve test etmeyi zorlaştırır — 15. hatta bu konuya döneceğiz.
// ── sayac.js
let adet = 0;
export const artir = () => ++adet;
export const oku = () => adet;
// İki farklı dosyadan içe aktarsan da AYNI adet paylaşılır.
Üç tuzak
1. Uzantı zorunludur. Tarayıcıda modül yolu bir URL'dir:
import { tutar } from "./bicim"; // ÇALIŞMAZ — 404
import { tutar } from "./bicim.js"; // doğru
import { tutar } from "bicim.js"; // ÇALIŞMAZ — "./" ya da "/" ile başlamalı
Uzantısız yazım Node.js ve paketleyicilerde çalışır; bu fark, "derleme aracında çalışan kod tarayıcıda çalışmıyor" şaşkınlığının klasik sebebidir.
2. Çıplak modül adları tarayıcıda çözülmez. import x from "lodash"
yazamazsın; tarayıcı "lodash"un nerede olduğunu bilmez. Bu adları çözen şey paketleyicidir
(9. bölüm) ya da <script type="importmap"> ile elle verilen eşlemedir.
3. Modüller file:// üzerinden çalışmaz. Modül istekleri CORS
kurallarına tabidir; dosyayı çift tıklayıp açtığında tarayıcı engeller. Geliştirme için basit
bir yerel sunucu gerekir. Bu sitede modül kullanılmamasının sebeplerinden biri de
budur — dersler file:// ile de açılabilsin diye klasik betikler
kullanılıyor.
Ayrıca modüller üst seviye await destekler (17. derste bahsedilen
istisna): modül gövdesinde doğrudan await yazabilirsin, ancak bu modülü içe
aktaran herkesi bekletir — kritik yolda dikkatli kullanılmalıdır.
05Dinamik import()
Statik import dosyanın tepesinde durur ve koşullu olamaz. Bir modülü
gerektiğinde yüklemek için fonksiyon biçimli import() kullanılır; bir
Promise döndürür:
dugme.addEventListener("click", async () => {
const { PdfUretici } = await import("./pdf-uretici.js"); // ilk tıklamada indirilir
new PdfUretici().yaz(veri);
});
Bu, kod bölmenin temelidir: nadiren kullanılan ağır bir özelliği (PDF üretimi, grafik kütüphanesi, harita) ilk yüklemeye dâhil etmezsin. 1. derste konuştuğumuz LCP ve INP metriklerini iyileştiren en etkili tekniklerden biridir. Yönlendirici tabanlı uygulamalarda (10. ve 11. hat) her sayfa ayrı bir parça olarak bu yolla yüklenir.
06Diğer modül sistemleri
ES modüllerinden önce ekosistem kendi çözümlerini üretti; eski kodda ve Node.js'te hâlâ karşına çıkarlar:
| ES Modülleri (ESM) | CommonJS (CJS) | |
|---|---|---|
| Sözdizimi | import / export | require() / module.exports |
| Nerede | Tarayıcı + Node.js | Node.js (geleneksel) |
| Yükleme | Asenkron, statik olarak çözülür | Senkron, çalışma anında |
| Koşullu içe aktarma | Yalnız dinamik import() ile | if içinde require serbest |
| Statik analiz | Mümkün → ağaç sarsma yapılabilir | Zor |
Node.js'te bir dosyanın hangisi olduğunu package.json içindeki
"type": "module" alanı ya da uzantı belirler (.mjs / .cjs).
İkisini karıştırmak Node dünyasının bilinen sürtünme noktasıdır ve 12. hatta ayrıntısıyla
göreceksin. Eskiden tarayıcı ve Node uyumunu birlikte sağlamak için UMD paketleri
üretilirdi; hâlâ CDN'lerde karşına çıkar.
07npm ve package.json
npm, JavaScript paket kayıt defteri ve onun komut satırı aracıdır (alternatifleri:
pnpm, yarn). Bir projenin kimliği package.json dosyasında durur:
{
"name": "basvuru-arayuz",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest"
},
"dependencies": { "react": "^18.3.1" }, // ÇALIŞMA anında gerekli
"devDependencies": { "vite": "^5.4.0" } // yalnız GELİŞTİRME/derleme sırasında
}
| Sürüm yazımı | İzin verdiği |
|---|---|
1.4.2 | Tam olarak o sürüm |
~1.4.2 | Yama güncellemeleri: 1.4.x |
^1.4.2 | Küçük sürümler: 1.x.x (varsayılan) |
* | Her şey — kullanma |
Anlamsal sürümleme (semver) ANA.KÜÇÜK.YAMA biçimindedir: ana sürüm
geriye dönük uyumu bozar, küçük sürüm özellik ekler, yama hata düzeltir. ^
işareti "uyumlu güncellemeleri al" demektir — ama bu, kütüphanenin kurala uyduğu
varsayımına dayanır ve her zaman uyulmaz.
Bu yüzden kilit dosyası (package-lock.json) vardır: kurulan her
paketin tam sürümünü ve bütünlük özetini kaydeder. Kurallar:
- Kilit dosyası sürüm kontrolüne eklenir — takımın ve CI'ın aynı ağacı kurmasını o sağlar.
- CI'da
npm installdeğilnpm ciçalıştırılır: kilidi birebir uygular,node_modules'ü sıfırdan kurar ve kilidi değiştirmez. node_modulessürüm kontrolüne eklenmez.
Bu, 18. hattaki CI/CD konusunun da temel maddesidir: yeniden üretilebilir yapı (reproducible build) demek, aynı girdiyle aynı çıktıyı almak demektir.
08Bağımlılık bir borçtur
npm'in gücü, milyonlarca hazır paket olmasıdır; riski de aynı yerdedir. Bir paket kurduğunda genellikle onu değil, bir ağacı kurarsın: tek bir paket onlarca geçişli bağımlılık getirebilir ve hepsi senin uygulamanla aynı yetkiyle çalışır.
- Tedarik zinciri riski. Ele geçirilmiş ya da kötü niyetle güncellenmiş bir alt
bağımlılık, derleme anında ya da çalışma anında kod çalıştırabilir. Kurumsal ortamda
önlemler: kilit dosyası, iç kayıt defteri/ayna, sürüm sabitleme, otomatik güvenlik
taraması (
npm audit, bağımlılık güncelleme botları) ve derleme betiklerinin gözden geçirilmesi. - Bakım riski. Bakımı bırakılmış bir paket, ana sürüm geçişlerinde seni kilitler.
- Boyut. Kullanıcıya inen her kilobayt bir maliyettir; birkaç satırlık iş için kütüphane eklemek kötü bir takastır.
Karar ölçütü basittir: bu paket ne kadar iş yapıyor, kaç bağımlılık getiriyor, ne
sıklıkla güncelleniyor ve ben aynı işi ne kadar sürede yazarım? Tarih biçimlendirme ya
da dizi yardımcıları gibi işler bugün büyük ölçüde standart kütüphaneyle (
Intl, dizi metotları) çözülebiliyor. Buna karşılık şifreleme, PDF üretimi ya da
tarih/saat dilimi hesapları için kendi çözümünü yazmak kötü bir fikirdir.
09Paketleyici ne yapar
Tarayıcı ES modüllerini anlıyorsa paketleyiciye neden ihtiyaç var? Cevap tek bir şey değil, bir listedir:
| İş | Ne kazandırır |
|---|---|
| Çıplak ad çözümleme | import x from "react" yazabilmek |
| Ağaç sarsma (tree shaking) | Kullanılmayan dışa aktarımları çıktıdan atar — ESM'in statik yapısı sayesinde |
| Kod bölme | Dinamik import()'ları ayrı parçalara böler |
| Küçültme (minify) | Boşluk ve uzun adları siler; sıkıştırmayla birlikte boyutu birkaç kat düşürür |
| Dönüştürme (transpile) | TypeScript ve JSX'i (9-11. hat) tarayıcının anlayacağı JavaScript'e çevirir |
| Varlık işleme | CSS, görsel ve yazı tiplerini bağımlılık grafiğine katar |
| İçerik damgalı ad | app.9f1c2b.js — 1. dersteki önbellek kuralını uygular |
| Kaynak eşlemesi (source map) | Tarayıcıda küçültülmüş kod yerine özgün kaynağı görmeni sağlar |
| Geliştirme sunucusu / HMR | Kaydettiğin anda sayfayı yenilemeden güncelleme |
Manzara: Vite bugün yeni projelerde yaygın varsayılandır (geliştirmede tarayıcının yerel modüllerini kullanır, üretim için toplar); webpack uzun süre standart olduğu için kurumsal kod tabanlarında hâlâ çok yaygındır; esbuild ve Rollup ise genelde bunların içinde ya da kütüphane paketlemede kullanılır. Angular ve React'in proje şablonları (10. ve 11. hat) bu araçları hazır yapılandırılmış getirir.
Kaynak eşlemesi hakkında bir üretim notu: küçültülmüş kodda hata ayıklamak neredeyse imkânsızdır, bu yüzden kaynak eşlemeleri üretilir — ama herkese açık yayınlanması kaynak kodunu ifşa eder. Yaygın çözüm, eşlemeleri hata izleme aracına yükleyip genel erişime kapatmaktır.
Derleme adımı ne zaman gerekmez
Her proje paketleyici istemez. Şu koşullarda saf ES modülleri (hatta klasik betikler)
yeterlidir: bağımlılık yok ya da çok az, TypeScript/JSX gibi dönüştürme gerektiren
bir dil yok, dosya sayısı yönetilebilir ve ilk yükleme boyutu zaten küçük. Kazancı
gerçektir: kurulacak araç yok, sürüm yükseltmesi yok, node_modules yok,
yıllar sonra açtığında hâlâ çalışıyor. Bu sitenin kararı budur — saf HTML/CSS/JS,
derleme adımı yok, önbellek damgası elle (?v=6). Bedeli de kabul edilmiştir:
ağaç sarsma ve otomatik kod bölme yok, çıplak paket adı kullanılamıyor, dosyalar
file:// ile açılabilsin diye modül bile kullanılmıyor. Karar bir moda
sorusu değil: hangi işi kimin yaptığını bilerek seçmek.
10Mini alıştırma — Modülleri kendi elinle kur
Yaklaşık 20 dakika · birkaç dosya + basit bir yerel sunucu
(editörünün canlı sunucu eklentisi ya da python3 -m http.server)
- Kur:
bicim.js,veri.jsveuygulama.jsyaz;uygulama.jsdiğer ikisini içe aktarsın ve HTML'etype="module"ile bağla. file://tuzağı: HTML dosyasını çift tıklayarak aç. Konsolda hangi hatayı gördün? Yerel sunucuyla tekrar aç.- Uzantı: içe aktarma yolundan
.jsuzantısını sil. Ne oldu? - Kapsam: modül içinde üst seviye bir
consttanımla ve konsoldawindowüzerinden erişmeyi dene. - Sıkı mod: modül içinde bildirilmemiş bir değişkene atama yap. Hata aldın mı?
- Adlandırılmış vs varsayılan: bir fonksiyonu her iki biçimde de dışa aktar. Adlandırılmışta yazımı bilerek yanlış yap — ne zaman hata verdi?
- Tekillik:
sayac.jsmodülünü iki farklı dosyadan içe aktar ve birinden artır, diğerinden oku. Aynı sayacı mı paylaştılar? - Yükleme sırası: modüllerin ve klasik betiklerin çalışma sırasını
console.logile karşılaştır. Modüldefergibi mi davrandı? - Dinamik içe aktarma: ağır bir modülü yalnız düğmeye basınca yükle. Network panelinde dosya ne zaman indi?
- Üst seviye
await: bir modülün gövdesindeawaitkullan ve onu içe aktaran dosyanın beklediğini gözle. - Döngüsel bağımlılık: A modülü B'yi, B de A'yı içe aktarsın. Değerlerden biri
undefinedgeldi mi? Neden? - Sürüm okuma: herhangi bir gerçek projenin
package.json'ını aç;^ile başlayan üç bağımlılık bul ve hangi sürümlere izin verdiklerini yaz. - Kilit dosyası: aynı projenin kilit dosyasında bir paketin kaç farklı sürümünün bulunduğunu ara. Neden birden çok olabilir?
- Karar tatbikatı: "tarihi '3 gün önce' biçiminde göster" işini bir paket
ekleyerek ve
Intl.RelativeTimeFormatile çözmeyi karşılaştır. Hangisi daha az borç?
11Kendini sına
ES modülleri klasik betiklerden hangi yönlerden farklıdır?
Beş fark vardır. (1) Kendi kapsamı — üst seviye değişkenler
küresel nesneye yazılmaz, dolayısıyla ad çakışması olmaz; klasik betiklerde her şey
paylaşılan kapsamdadır. (2) Her zaman sıkı mod — "use strict" yazmaya
gerek yoktur. (3) defer gibi yüklenir — belge ayrıştırmasını
durdurmaz, DOM hazır olduktan sonra ve yazıldıkları sırayla çalışır. (4) Bir kez
değerlendirilir — aynı modülü on dosyadan içe aktarsan da tek örnek vardır, yani
modülde tutulan üst seviye durum uygulama genelinde paylaşılır (tekil davranışı).
(5) İçe aktarımlar statiktir — kod çalışmadan önce çözülür; bu, paketleyicilerin
ağaç sarsma yapabilmesinin temelidir. Tarayıcıya özgü üç tuzağı da bilmek gerekir:
yol bir URL olduğu için .js uzantısı zorunludur ve yol
./ ya da / ile başlamalıdır; çıplak paket adları
("react") tarayıcıda çözülmez, paketleyici ya da içe aktarma haritası gerekir;
ve modüller CORS'a tabi olduğu için file:// üzerinden çalışmaz, yerel
bir sunucu gerekir. Modüller ayrıca üst seviye await destekler.
Tarayıcılar ES modüllerini destekliyorsa paketleyiciye neden hâlâ ihtiyaç var?
Çünkü paketleyici yalnız "dosyaları birleştiren" bir araç değildir;
bir listeyi birden yapar. (1) Çıplak ad çözümleme — import x from "react"
yazabilmeyi sağlar. (2) Ağaç sarsma — kullanılmayan dışa aktarımları çıktıdan atar;
büyük kütüphanelerde boyutun çoğunu bu kazandırır. (3) Kod bölme — dinamik
import()'ları ayrı parçalara ayırıp ilk yüklemeyi küçültür.
(4) Küçültme ve sıkıştırma. (5) Dönüştürme — TypeScript ve JSX tarayıcının
anlamadığı sözdizimleridir, birinin çevirmesi gerekir. (6) Varlık işleme — CSS,
görsel ve yazı tiplerini bağımlılık grafiğine katar. (7) İçerik damgalı dosya adı —
uzun ömürlü önbelleği güvenle kullanmayı sağlar. (8) Kaynak eşlemesi ve
geliştirme sunucusu/HMR — geliştirme deneyimi. Yine de her proje paketleyici
gerektirmez: bağımlılığı az, dönüştürme gerektirmeyen, dosya sayısı yönetilebilir projelerde
saf ES modülleri yeterlidir ve kazancı gerçektir — kurulacak araç, sürdürülecek
yapılandırma ve node_modules olmaz, proje yıllar sonra da açılır. Bu sitenin
kararı da budur.
package.json ile package-lock.json arasındaki fark nedir? Kilit dosyası neden sürüm kontrolüne eklenir?
package.json niyeti yazar: hangi paketlerin, hangi
sürüm aralığında istendiğini. ^1.4.2 "1.x.x içinde uyumlu her şey"
demektir; yani aynı dosyadan bugün ve altı ay sonra kurulum yapmak farklı sürümler
getirebilir. package-lock.json ise gerçeği yazar: kurulan her paketin
(geçişli bağımlılıklar dâhil) tam sürümü, indirileceği adres ve bütünlük özeti.
Kilit dosyası sürüm kontrolüne eklenir çünkü yeniden üretilebilir yapı ancak böyle
sağlanır: takım arkadaşın, CI sunucusu ve üretim ortamı birebir aynı ağacı kurar. Aksi
hâlde "benim makinemde çalışıyor" hataları ve ancak üretimde ortaya çıkan sürüm
uyuşmazlıkları yaşanır. CI'da npm install yerine npm ci
kullanılır: kilidi birebir uygular, node_modules'ü sıfırdan kurar ve kilidi
değiştirmez. node_modules ise sürüm kontrolüne eklenmez;
kilit dosyasından yeniden üretilebilir olduğu için gereksizdir ve depoyu şişirir. Ek olarak
kilit dosyası bir güvenlik aracıdır: bütünlük özetleri sayesinde beklenmedik bir
paket içeriği fark edilir ve tedarik zinciri riski daralır.
Bir npm paketi eklemeye karar verirken neye bakarsın?
Bağımlılık bir kolaylık değil, üstlenilen bir borçtur: her
paket bakım, güvenlik ve boyut maliyeti getirir. Baktığım şeyler: (1) Ne kadar iş
yapıyor? Birkaç satırlık bir yardımcı için paket eklemem — bugün tarih ve sayı
biçimlendirme Intl ile, dizi işleri standart metotlarla çözülüyor. Buna
karşılık şifreleme, PDF üretimi ya da saat dilimi hesabı gibi işlerde kendi çözümümü
yazmak daha kötü bir karardır. (2) Kaç geçişli bağımlılık getiriyor? Tek bir paket
onlarca alt bağımlılık kurabilir ve hepsi uygulamayla aynı yetkiyle çalışır — bu doğrudan
tedarik zinciri riskidir. (3) Bakım durumu: son yayın tarihi, açık sorunlar,
ana sürüm geçmişi, tek kişiye mi bağlı. (4) Boyut ve ağaç sarsmaya uygunluk:
kullanıcıya inen kilobayt bir maliyettir. (5) Lisans — kurumsal ve kamu
projelerinde bu bir hukuki maddedir. Riski azaltan pratikler: kilit dosyasını depoya
eklemek, CI'da npm ci kullanmak, düzenli güvenlik taraması yapmak, kurumsal
ortamda iç kayıt defteri/ayna kullanmak ve bağımlılık güncellemelerini otomatik ama
gözden geçirilerek almak. 18. hattaki boru hattı bu adımların çalıştığı yerdir.
12Sınav köşesi
Yazılıda nasıl sorulur
(1) ES modülleri nedir, export/import nasıl kullanılır?
(2) Named export ile default export farkı. (3) Modüllerin klasik betiklerden farkları.
(4) Dinamik import() ne işe yarar? (5) CommonJS ile ES modülleri farkı.
(6) npm nedir; package.json içinde neler bulunur?
(7) dependencies ile devDependencies farkı.
(8) Semantic versioning; ^ ve ~ ne anlama gelir?
(9) package-lock.json neden vardır? (10) Bundler nedir, ne işe yarar?
(11) Tree shaking ve code splitting nedir? (12) Source map nedir?
Sözlüde nasıl anlatılır — 2 dakikalık taslak
Düzen: (1) Problem — "modüllerden önce kod küresel kapsamda dururdu; ad çakışması ve
betik sırası elle yönetilirdi, IIFE ile kapsam kurulurdu ama bağımlılık sırası yine
sorundu." (2) Çözüm — "ES modülleri kendi kapsamını, sıkı modu ve statik bağımlılık
çözümlemesini getirir; defer gibi yüklenir ve bir kez değerlendirilir,
yani modül durumu uygulama genelinde paylaşılır." (3) Kıdem vuruşu — "tarayıcıda uzantı
zorunludur, çıplak paket adları çözülmez ve modüller file:// üzerinden
çalışmaz; bu üçü 'derleme aracında çalışıyor, tarayıcıda çalışmıyor' şaşkınlığının
sebebidir." (4) Ekosistem — "npm bağımlılıkları getirir; package.json
niyeti, kilit dosyası gerçeği yazar. CI'da npm ci ile kilidi birebir
uygularım, yeniden üretilebilir yapı bunu gerektirir."
(5) Paketleyici ve karar — "paketleyici çıplak ad çözer, ağaç sarsar, kod böler,
küçültür, TypeScript/JSX'i çevirir ve içerik damgalı dosya adı üretir. Ama her proje
derleme adımı istemez: bağımlılığı az ve dönüştürme gerektirmeyen bir projede saf
modüllerle kalmak bakım maliyetini düşürür — hangi işi kimin yaptığını bilerek seçerim."
