~/zafer
Tüm yazılara dön
2 dk okuma

Bir Zod Paketini Hem CommonJS Hem ESM'e Derlemek

packages/schemas üç farklı runtime tarafından import ediliyor: NestJS (CommonJS ağırlıklı), Next.js (ESM), Vite (ESM). Aynı Zod şemasının üçünde de sorunsuz çalışması için paket tek bir formata değil, ikisine birden derleniyor.

İki ayrı tsconfig

// packages/schemas/tsconfig.cjs.json
{
  "extends": "@myself/typescript-config/base.json",
  "compilerOptions": { "module": "node16", "moduleResolution": "node16", "outDir": "dist/cjs", "declaration": true, "noEmit": false }
}
// packages/schemas/tsconfig.esm.json
{
  "extends": "@myself/typescript-config/base.json",
  "compilerOptions": { "module": "esnext", "moduleResolution": "bundler", "outDir": "dist/esm", "declaration": true, "noEmit": false }
}

Build script ikisini sırayla çalıştırıyor: tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json. Aynı src/ iki farklı outDir'a, iki farklı module hedefiyle derleniyor.

Tüketicinin hangi dosyayı alacağını exports belirliyor

{
  "main": "./dist/cjs/index.js",
  "module": "./dist/esm/index.js",
  "types": "./dist/cjs/index.d.ts",
  "exports": {
    ".": { "types": "./dist/cjs/index.d.ts", "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js" }
  }
}

Node'un require()require anahtarına, bir bundler'ın import'u import anahtarına gidiyor — Node.js kendi çözümleme algoritmasını, Next.js/Vite kendi bundler'larınınkini kullanıyor, hiçbiri yanlış formatı almıyor.

Neden tek format yetmiyor

Sadece CJS derlenirse Next.js/Vite'ın ESM tree-shaking'i düzgün çalışmaz; sadece ESM derlenirse NestJS'in require() tabanlı module yükleme zinciri kırılır. İki ayrı outDir'a derlemek, tek bir kaynak dosyadan (src/post.ts gibi) her iki dünyaya da doğru formatta çıktı üretmenin en basit yolu — bundler'a "ikisini de destekle" demek yerine, iki gerçek derleme çıktısı üretip seçimi exports haritasına bırakıyoruz.