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

Vimaj8 dk okuma
Sarı JS kare logosu yanında iki dosya ikonu sol teal ESM mjs etiketli ok yukarı import sağ coral CJS cjs etiketli ok aşağı require ortada karşılaştırma çizgisi

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ı

İşlemCommonJSESM
Importconst x = require('./x')import x from './x.js'
Named importconst { a } = require('./x')import { a } from './x.js'
Default exportmodule.exports = objexport default obj
Named exportmodule.exports.a = aexport 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.

VS Code dark tema editörde iki tab yan yana sol math mjs ESM export ve import syntax sağ math cjs CommonJS module exports ve require syntax JavaScript kod

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ır

CommonJS'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

  1. Import path'lerinde uzantı unutmak. ESM'de "./file" yerine "./file.js" yazmak gerek
  2. Karma kullanım. Tek dosyada hem require hem import; çalışmaz
  3. Tree shaking için yanlış import. "import * as" tree shaking'i devre dışı bırakır
  4. JSON import'u. ESM'de JSON import farklı; assert syntax gerek
  5. Dual package hazard. Aynı paketin CJS ve ESM versiyonları farklı state tutabilir
Tree shaking akış diyagramı solda utils js modülünde üç fonksiyon a b c kutusu ortada build aşaması ok sağda bundle çıktısında sadece a fonksiyonu yeşil kalır b ve c gri solmuş

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.

 Vimaj