JavaScript Modules: Import/Export Sistemi

JavaScript Modules: Import/Export Sistemi
JavaScript modül sistemi, kodu bağımsız, yeniden kullanılabilir parçalara ayırmanın resmi yoludur. ES6 modülleri (ESM), import ve export anahtar kelimeleri ile statik modül yapısı sunar. Bu rehberde modül sisteminin temellerinden, dinamik import, barrel dosyaları ve tree shaking gibi ileri konulara kadar her şeyi ele alıyoruz.
1. Named Export ve Import
Named export, bir modülden birden fazla değeri dışa aktarmanın ve seçici şekilde içe aktarmanın yoludur.
// utils/matematik.js — Named exports
export const PI = 3.14159265359;
export function toplam(a, b) {
return a + b;
}
export function carpim(a, b) {
return a * b;
}
export class Hesaplayici {
constructor(baslangic = 0) {
this.deger = baslangic;
}
topla(n) { this.deger += n; return this; }
cikar(n) { this.deger -= n; return this; }
sonuc() { return this.deger; }
}
// main.js — Named imports
import { toplam, carpim, PI } from './utils/matematik.js';
console.log(toplam(3, 5)); // 8
console.log(PI); // 3.14159...
// Alias ile yeniden adlandırma
import { toplam as add, carpim as multiply } from './utils/matematik.js';
console.log(add(10, 20)); // 30
// Tüm export'ları namespace olarak alma
import * as Matematik from './utils/matematik.js';
console.log(Matematik.toplam(1, 2)); // 3
console.log(Matematik.PI); // 3.14159...
2. Default Export
Her modül bir adet default export'a sahip olabilir. Default export, import sırasında herhangi bir isimle alınabilir.
// services/apiClient.js — Default export
export default class ApiClient {
#baseUrl;
#headers;
constructor(baseUrl, options = {}) {
this.#baseUrl = baseUrl;
this.#headers = {
'Content-Type': 'application/json',
...options.headers
};
}
async get(endpoint) {
const yanit = await fetch(`${this.#baseUrl}${endpoint}`, {
headers: this.#headers
});
if (!yanit.ok) throw new Error(`HTTP ${yanit.status}`);
return yanit.json();
}
async post(endpoint, veri) {
const yanit = await fetch(`${this.#baseUrl}${endpoint}`, {
method: 'POST',
headers: this.#headers,
body: JSON.stringify(veri)
});
return yanit.json();
}
}
// main.js — Default import (isim serbestçe seçilebilir)
import ApiClient from './services/apiClient.js';
import Http from './services/apiClient.js'; // Farklı isim de olabilir
const api = new ApiClient('https://api.example.com');
const kullanicilar = await api.get('/users');
// Default + named export birlikte
// services/auth.js
export default function girisYap(email, sifre) { /* ... */ }
export function cikisYap() { /* ... */ }
export function tokenYenile() { /* ... */ }
// Import
import girisYap, { cikisYap, tokenYenile } from './services/auth.js';
3. Dinamik Import ve Code Splitting
Dinamik import() fonksiyonu, modülleri çalışma zamanında koşullu veya tembel (lazy) olarak yüklemenizi sağlar. Bundler'lar bu yapıyı otomatik olarak code splitting için kullanır.
// Koşullu yükleme
async function grafik Goster(tip) {
let GrafikModulu;
if (tip === "bar") {
GrafikModulu = await import('./grafikler/bar.js');
} else if (tip === "pasta") {
GrafikModulu = await import('./grafikler/pasta.js');
}
const grafik = new GrafikModulu.default(veri);
grafik.ciz();
}
// Tembel yükleme — route bazlı
const rotalar = {
'/': () => import('./sayfalar/AnaSayfa.js'),
'/hakkinda': () => import('./sayfalar/Hakkinda.js'),
'/iletisim': () => import('./sayfalar/Iletisim.js')
};
async function rotayiYukle(yol) {
const yukleyici = rotalar[yol];
if (!yukleyici) throw new Error('404: Sayfa bulunamadı');
const modul = await yukleyici();
modul.default.render();
}
// Feature detection ile polyfill yükleme
if (!window.IntersectionObserver) {
await import('./polyfills/intersection-observer.js');
}
// Top-level await (ES2022, modül ortamında)
const config = await import(`./config/${process.env.NODE_ENV}.js`);
console.log(config.default.apiUrl);
4. Re-export ve Barrel Dosyaları
Barrel dosyaları, birden fazla modülü tek bir giriş noktasından dışa aktararak import ifadelerini sadeleştirir.
// utils/index.js — Barrel dosyası
export { toplam, carpim, PI } from './matematik.js';
export { formatTarih, tarihFarki } from './tarih.js';
export { dogrula, temizle } from './dogrulama.js';
export { default as ApiClient } from './apiClient.js';
// Tümünü re-export
export * from './string-helpers.js';
// İsim çakışmasını önleme
export { format as tarihFormat } from './tarih.js';
export { format as sayiFormat } from './sayi.js';
// Kullanım — tek satırda birden fazla modülden import
import { toplam, formatTarih, dogrula, ApiClient } from './utils/index.js';
// veya
import { toplam, formatTarih, dogrula } from './utils';
export * kullanırken isim çakışmalarına dikkat edin. Ayrıca büyük barrel dosyaları tree shaking'i zorlaştırabilir. Bundler'ınızın barrel dosyalarını düzgün optimize ettiğinden emin olun.
5. CommonJS vs ESM Karşılaştırma
// CommonJS (Node.js geleneksel)
const fs = require('fs');
const { readFile } = require('fs');
module.exports = { fonksiyon1, fonksiyon2 };
module.exports = varsayilanFonksiyon;
// ESM (Modern standart)
import fs from 'fs';
import { readFile } from 'fs';
export { fonksiyon1, fonksiyon2 };
export default varsayilanFonksiyon;
// Temel farklar:
// 1. ESM statiktir (derleme zamanı analiz), CJS dinamiktir
// 2. ESM'de import'lar hoist edilir, CJS'de require() sıralıdır
// 3. ESM strict mode'dur, CJS değildir
// 4. ESM'de top-level await kullanılabilir
// 5. ESM'de __dirname/__filename yoktur
// ESM'de __dirname alternatifi
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// package.json ile modül tipi belirleme
// { "type": "module" } → .js dosyaları ESM
// { "type": "commonjs" } → .js dosyaları CJS (varsayılan)
// .mjs → her zaman ESM
// .cjs → her zaman CJS
package.json'da "type": "module" ayarı ile tüm .js dosyalarını ESM olarak işaretleyebilirsiniz.
Sonuç
JavaScript modül sistemi, büyük ölçekli uygulamaları organize etmenin temel aracıdır. Named ve default export, dinamik import ile tembel yükleme, barrel dosyaları ile modül organizasyonu ve ESM/CJS farkları konularında bilgi sahibi olmak, modern JavaScript geliştirmenin olmazsa olmazıdır. Projelerinizde modüler mimariyi benimseyerek kodunuzun bakımını ve test edilebilirliğini artırın.