JAVASCRIPT MODÜL SİSTEMİ ESM COMMONJS KARŞILAŞTIRMAK

Modern JavaScript projeleri çoğunlukla ESM kullanır; tarayıcılar yerli olarak destekler, build tool'lar (Vite, esbuild, webpack) ESM odaklı çalışır. CommonJS Node.js ekosisteminde hâlâ baskın; özellikle eski paketler ve sunucu tarafı için. Hangi sistemi kullanacağınızı bilmek modern JavaScript için temel.
1. CommonJS (CJS)
Node.js'in geleneksel modül sistemi. 2009'dan beri kullanımda. Senkron yükleme yapar. İki sistemin modül davranışını karşılaştırmak isteyenler için web teknolojileri dokümantasyonu import/export semantiğini ayrıntılı açıklar.
// math.js (CommonJS)
function topla(a, b) {
return a + b;
}
module.exports = { topla };
// app.js
const { topla } = require('./math');
console.log(topla(2, 3));Karakteristikleri:
- require: Modül yükleme
- module.exports: Modülden çıkış
- Senkron: require çağrısı modül yüklenene kadar bekler
- Runtime: Modüller çalışma zamanında yüklenir
- Dinamik: require ifadesinin içine değişken yerleştirilebilir
2. ES Modules (ESM)
ECMAScript 2015 ile gelen resmi standart. Modern JavaScript'in tercih ettiği sistem.
// math.js (ESM)
export function topla(a, b) {
return a + b;
}
// app.js
import { topla } from './math.js';
console.log(topla(2, 3));Karakteristikleri:
- import / export: Modül yükleme ve çıkış
- Asenkron: Modüller paralel yüklenebilir
- Statik: import ifadesi build zamanında çözümlenir
- Tree shaking: Kullanılmayan kod build'den çıkarılır
- Tarayıcı desteği: Modern tarayıcılarda yerli
3. Syntax farkları
| İşlem | CommonJS | ESM |
|---|---|---|
| Import | const x = require('./x') | import x from './x.js' |
| Named import | const { a } = require('./x') | import { a } from './x.js' |
| Default export | module.exports = obj | export default obj |
| Named export | module.exports.a = a | export const a = ... |
4. Node.js'te yapılandırma
Node.js varsayılan olarak CommonJS kullanır. ESM kullanmak için iki yöntem:
1. package.json'da type: module
{
"name": "myproject",
"type": "module",
"version": "1.0.0"
}Bu ayarla tüm .js dosyaları ESM olarak yorumlanır. CommonJS dosyaları .cjs uzantısı ile kullanılır.
2. .mjs uzantısı
Karma kullanım için pratik; tek tek dosyalar ESM olur.
5. Tarayıcı kullanımı
Tarayıcılarda ESM yerli destekleniyor. <script type="module"> attribute'ı gerekli:
<script type="module">
import { greet } from './greet.js';
greet('World');
</script>CommonJS tarayıcıda doğrudan çalışmaz; webpack veya benzeri bundler ile derlenmesi gerekir.

6. Tree shaking ve performans
ESM'in en büyük avantajlarından biri tree shaking. Statik import yapısı sayesinde build tool'lar kullanılmayan kodları otomatik çıkarır.
// utils.js (ESM)
export const a = () => 'A';
export const b = () => 'B';
export const c = () => 'C';
// app.js
import { a } from './utils.js';
console.log(a());
// Build sonrası: sadece 'a' fonksiyonu bundle'a girer
// 'b' ve 'c' kullanılmadığı için çıkarılırCommonJS'te bu otomatik olmaz; require dynamic olduğu için build tool hangi fonksiyonun kullanıldığını çalışma zamanına kadar bilemez. Bundle boyutu daha büyük olur.
7. Dynamic import
ESM'de runtime'da modül yükleme için import() fonksiyonu var:
async function loadModule() {
const module = await import('./math.js');
return module.topla(2, 3);
}Code splitting için kritik; sayfa açıldığında değil ihtiyaç olduğunda modül yüklenir. Lazy loading'in temeli.
8. Ortak senaryolar
CJS modülünü ESM'de kullanma
Node.js bu interop'u otomatik yapar; çoğu durumda çalışır. Bazı paketlerde özel ayar gerekebilir.
// Modern ESM kullanım
import legacyPkg from 'legacy-pkg';
console.log(legacyPkg.utility());ESM modülünü CJS'de kullanma
CJS'te statik require ile ESM modülü yüklenmez; sadece dynamic import çalışır.
async function main() {
const { greet } = await import('modern-pkg');
console.log(greet());
}
main();9. Hangi sistemi kullanmalı?
Yeni projeler için: ESM
Modern bütünleşme, tree shaking, tarayıcı uyumu nedeniyle yeni projelerin tamamı ESM olmalı.
Eski projeler için: kademeli geçiş
Mevcut CommonJS projesi varsa zorlama gerekmez. Yeni eklenen kod ESM olabilir; eski kod ihtiyaç oldukça migrate edilir.
Library yazarken: dual package
NPM paketi yayınlıyorsanız hem CJS hem ESM versiyon sağlamak en kapsayıcı:
{
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}10. ESM'de __dirname alternatifi
// CommonJS
const path = require('path');
const fullPath = path.join(__dirname, 'file.txt');
// ESM
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);11. Sık Karşılaşılan Yanılgılar
- Import path'lerinde uzantı unutmak. ESM'de "./file" yerine "./file.js" yazmak gerek
- Karma kullanım. Tek dosyada hem require hem import; çalışmaz
- Tree shaking için yanlış import. "import * as" tree shaking'i devre dışı bırakır
- JSON import'u. ESM'de JSON import farklı; assert syntax gerek
- Dual package hazard. Aynı paketin CJS ve ESM versiyonları farklı state tutabilir

12. Disiplinin Yerleşmesi
Modül sistemleri modern JavaScript ekosisteminin temelidir. Bilgiyi sıralı yol haritasıyla edinmek için uygulamalı JavaScript eğitimi ESM, CommonJS ve modern modül yönetimi konularını birlikte aktarır.
Toparlarsak
JavaScript'te ESM ve CommonJS iki ana modül sistemi. CommonJS Node.js'in eski standartı; senkron, dinamik, runtime tabanlı. ESM modern standart; asenkron, statik, tree shaking destekli. Yeni projeler ESM tercih etmeli; mevcut projeler kademeli geçiş yapmalı. NPM paketleri yayınlanırken dual package (her ikisini destekleme) en kapsayıcı yaklaşım. Modern build tool'lar ESM odaklı çalışır; geçiş JavaScript ekosisteminin geleceği.
Sıkça Sorulan Sorular
ESM mi CommonJS mi daha hızlı?
ESM daha hızlıdır; özellikle tree shaking sayesinde bundle boyutu küçük olur. Statik import yapısı build tool'lara optimizasyon imkanı tanır. CommonJS dinamik require ile bu optimizasyonu yapamaz. Çalışma zamanı performansında küçük fark var; asıl avantaj build çıktısının boyutu.
Node.js varsayılan olarak hangisini kullanır?
Node.js 22 itibarıyla varsayılan hâlâ CommonJS. ESM kullanmak için package.json'a 'type: module' eklemek veya .mjs uzantısı kullanmak gerek. Node.js ESM desteği 12. sürümle başladı; bugün tam destek var. Yeni projelerde ESM tercih edilir; eski projelerde CommonJS sürdürülür.
Bir projede hem CJS hem ESM kullanılabilir mi?
Evet ama karmaşık. Tek dosyada karışım çalışmaz; ama farklı dosyalar farklı sistem olabilir. .js uzantısı package.json'daki type'a göre yorumlanır; .cjs zorla CommonJS, .mjs zorla ESM. Dynamic import ile CJS modülü ESM'den çağrılabilir. Karma kullanım yönetim yükü artırır; mümkünse tek sistem tercih edilir.
Tree shaking neden ESM'de çalışıyor?
ESM statik import yapısı sayesinde. Build tool kodu analiz ederken 'app.js dosyası utils.js'ten sadece function a'yı import ediyor' bilgisini görür ve b ile c'yi bundle'a koymaz. CommonJS dynamic require kullanır; build tool hangi fonksiyonun kullanıldığını çalışma zamanına kadar bilemez. Bu yüzden tree shaking yapamaz.
import path'inde uzantı zorunlu mu?
ESM'de evet; Node.js katı modda uzantıyı zorunlu kılar (.js, .mjs). CommonJS'te isteğe bağlıydı. Bu fark yeni geçiş yapanlar için tipik 'çalışmıyor' sebebi. Build tool'ları (Webpack, Vite) genelde uzantısız import'a izin verir; ama production build'de hata verebilir. Doğru pratik: her import'a uzantı eklemek.
NPM'de yayınlamak için hangi sistemi seçmeli?
Dual package (her ikisi) en kapsayıcı yaklaşım. package.json'da exports field ile hem 'import' hem 'require' yolu belirtilir. Build tool'ları (rollup, esbuild) iki çıktı üretir: index.cjs ve index.mjs. Kullanıcı paketinizi hangi sistemde kullanırsa kullansın çalışır. Tek sistem seçmek istiyorsanız modern ESM tercih edilir.
__dirname ve __filename ESM'de neden farklı?
Bu CommonJS özel global değişkenleriydi; ESM standartlarında yok. ESM'de import.meta.url ile dosya yolu alınır; url modülü ile path'e çevrilir. Bu küçük detay eski CJS kodunu ESM'ye taşırken en <strong>sık karşılaşılan</strong> sorunlardan. ESM standardının daha modüler ve standart-yakın olmaya çalışması nedeniyle.


