Yazılarımız

OfisData

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

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

JavaScript yıllarca modül sistemi olmayan bir dildi. Tüm kodun aynı global scope'ta çalışması büyük projelerde kabusa dönüştü. Node.js 2009'da CommonJS (require/module.exports) ile modül sistemi getirdi; 2015'te ECMAScript 6 standardı ESM (import/export) ile resmi modül syntax'ı tanımlandı. Bugün iki sistem paralel kullanılıyor; geliştiriciler hangisini ne zaman seçeceği konusunda hâlâ kafa karıştırıyor.

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. İ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. Hangi sistemi kullanacağınızı bilmek modern JavaScript için temel.

İki modül sistemi arasındaki fark syntax'tan ibaret olsaydı mesele olmazdı: ESM statik analiz edilir, CommonJS çalışma anında çözülür — ve bu tek fark tree-shaking'den dosya uzantısına, Node.js yapılandırmasından geçiş stratejisine kadar her kararı şekillendirir.

CommonJS (CJS)

Node.js'in geleneksel modül sistemi. 2009'dan beri kullanımda. Senkron yükleme yapar.

// 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

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

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 = ...

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.

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

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.

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.

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();

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"
    }
  }
}

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);

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ş

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.

 Vimaj