← Kursa Dön
📄 Text · 30 min

Kod Kalitesi: ESLint ve Prettier

Neden Otomatik Kod Kalitesi?

Bir ekipte beş geliştirici olduğunu düşün. Biri tab kullanıyor, diğeri boşluk. Biri tek tırnak seviyor, diğeri çift tırnak. Biri fonksiyon sonuna noktalı virgül koyuyor, diğeri koymuyor. Kodlar bir araya geldiğinde tutarsız bir karmaşa oluşuyor — okunması zor, review'u sancılı, merge conflict'leri acı verici.

Daha kötüsü: biri == kullanıyor (=== yerine), biri kullanılmayan değişkenleri silmek yerine bırakıyor, biri any tipini rahatça kullanıyor. Bunlar sadece stil sorunu değil — hata kaynağı.

Analoji: Bir hastanedeki hijyen protokolünü düşün. Her doktor kendi kafasına göre ellerini yıkasa, bazısı yıkamasa, bazısı sadece su ile yıkasa ne olur? Enfeksiyon kaçınılmaz. Otomatik dezenfeksiyon istasyonları bu sorunu çözer — herkes aynı standart prosedürü uygular, düşünmesine gerek kalmaz. ESLint ve Prettier, kodunun "hijyen protokolü"dür.

Bu sorunların çözümü: otomatik araçlar. İnsan gözüyle her kod satırını denetlemek yerine, araçların otomatik olarak:

  1. Hataları tespit etmesini (ESLint)

  2. Formatlamayı düzeltmesini (Prettier)

  3. Commit öncesi kontrol yapmasını (Husky + lint-staged)

Bu üçlü birlikte çalıştığında ekibin kod kalitesi otopilotta olur.


ESLint: Kod Kalite Bekçisi

ESLint, JavaScript/TypeScript kodunu statik olarak analiz eder ve potansiyel hataları, kötü pratikleri, stil ihlallerini tespit eder. Kodu çalıştırmadan, sadece okuyarak sorunları bulur.

Bir editörün (düzeltmen) yazını okuması gibi düşün: yazım hatalarını, dilbilgisi sorunlarını, tutarsızlıkları işaretler — ama içeriği değiştirmez, sana bildirir.

Kurulum

# ESLint 9+ (Flat Config)
npm install -D eslint @eslint/js typescript-eslint

# TypeScript desteği
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin

Yapılandırma (Flat Config — ESLint 9+)

ESLint 9 ile birlikte yeni "flat config" formatına geçildi. Eski .eslintrc yerine eslint.config.js kullanılır:

// eslint.config.js
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  // Temel önerilen kurallar
  eslint.configs.recommended,

  // TypeScript önerilen kurallar
  ...tseslint.configs.recommended,

  // Özel kurallar
  {
    rules: {
      // Hata önleme
      "no-unused-vars": "off", // TS versiyonunu kullan
      "@typescript-eslint/no-unused-vars": ["error", {
        argsIgnorePattern: "^_",        // _param gibi olanları yoksay
        varsIgnorePattern: "^_",
      }],
      "@typescript-eslint/no-explicit-any": "warn",
      "no-console": ["warn", { allow: ["warn", "error"] }],

      // Best practice
      "eqeqeq": ["error", "always"],          // === kullan
      "no-var": "error",                        // var kullanma
      "prefer-const": "error",                  // Değişmeyen let → const
      "no-throw-literal": "error",              // throw "hata" değil, throw new Error
      "curly": ["error", "multi-line"],         // if sonrası {} zorunlu

      // TypeScript specific
      "@typescript-eslint/explicit-function-return-type": "off",
      "@typescript-eslint/no-non-null-assertion": "warn",
    },
  },

  // Test dosyaları için gevşetme
  {
    files: ["**/*.test.ts", "**/*.spec.ts"],
    rules: {
      "@typescript-eslint/no-explicit-any": "off",
      "no-console": "off",
    },
  },

  // İgnore patterns
  {
    ignores: ["dist/", "node_modules/", "coverage/"],
  }
);

ESLint 9 vs Eski Sürümler

ESLint 9 öncesinde .eslintrc.json veya .eslintrc.js kullanılırdı. İki format arasındaki farkları bilmek önemli çünkü birçok tutorial hâlâ eski formatta:

// ❌ ESKİ FORMAT (.eslintrc.js) — ESLint 8 ve altı
module.exports = {
  parser: "@typescript-eslint/parser",
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
  ],
  plugins: ["@typescript-eslint"],
  rules: {
    "no-var": "error",
  },
};

// ✅ YENİ FORMAT (eslint.config.js) — ESLint 9+
// Flat config: daha basit, daha anlaşılır, cascade yok
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    rules: {
      "no-var": "error",
    },
  }
);

// Farklar:
// 1. extends/plugins yerine doğrudan import
// 2. JSON yerine JavaScript (tip güvenliği, otomatik tamamlama)
// 3. Dosya bazlı override daha sezgisel
// 4. Kaskad (cascade) yok — yukarıdan aşağı, basit

💡 İpucu: Yeni projelerde her zaman ESLint 9+ flat config kullan. Eski projelerdeki .eslintrc dosyasını flat config'e migrate etmek için npx @eslint/migrate-config .eslintrc.json komutunu kullanabilirsin.

ESLint Kuralları Derinlemesine

Kurallar üç seviyede ayarlanır:

  • "off" veya 0 — Kural kapalı

  • "warn" veya 1 — Uyarı (sarı)

  • "error" veya 2 — Hata (kırmızı, build'i durdurur)

// Örnek: ESLint ne yakalar?

// ❌ no-unused-vars: Kullanılmayan değişken
const unused = "silinmeli"; // eslint: error

// ❌ eqeqeq: == yerine === kullan
if (x == null) { } // eslint: error, === kullan

// ❌ no-var: var kullanma
var oldStyle = true; // eslint: error, let/const kullan

// ❌ no-console: Production'da console.log olmamalı
console.log("debug"); // eslint: warn

// ❌ @typescript-eslint/no-explicit-any: any kullanma
function process(data: any) { } // eslint: warn

// ✅ Düzeltilmiş versiyonlar
const _unused = "underscore prefix ile OK";
if (x === null) { }
const modernStyle = true;
console.error("Hata!"); // error/warn OK
function process(data: unknown) { }

Önemli ESLint Kuralları Rehberi

// === Hata Önleme Kuralları ===

// no-undef: Tanımlanmamış değişken kullanımı
// konsol.log("test"); // ❌ konsol tanımlı değil (typo)

// no-dupe-keys: Nesne'de tekrar eden anahtar
// const obj = { a: 1, b: 2, a: 3 }; // ❌ 'a' iki kez var

// no-unreachable: return sonrası erişilemez kod
// function example() { return 1; console.log("asla"); } // ❌

// no-constant-condition: Sabit koşul
// if (true) { } // ❌ Her zaman true — mantık hatası olabilir

// === Güvenlik Kuralları ===

// no-eval: eval() kullanımını yasakla
// eval("alert('XSS riski!')"); // ❌ Güvenlik açığı

// no-implied-eval: setTimeout/setInterval'da string
// setTimeout("alert('hello')", 100); // ❌ eval gibi çalışır
// setTimeout(() => alert("hello"), 100); // ✅ Fonksiyon kullan

// === TypeScript Özel Kuralları ===

// @typescript-eslint/no-floating-promises: await unutma
// async function loadData() {
//   fetchData(); // ❌ await yok — hata sessizce yutulur
//   await fetchData(); // ✅
// }

// @typescript-eslint/no-misused-promises: Promise'i yanlış kullanma
// const isValid = items.filter(async item => { // ❌ filter async beklemez
//   return await validateItem(item);
// });

ESLint Çalıştırma

# Tüm dosyaları kontrol et
npx eslint src/

# Otomatik düzeltilebilenleri düzelt
npx eslint src/ --fix

# Belirli dosya
npx eslint src/utils/math.ts

# Belirli kuralı devre dışı bırakarak çalıştır
npx eslint src/ --rule '{"no-console": "off"}'

# Cache kullanarak hızlandır (sadece değişen dosyaları kontrol et)
npx eslint src/ --cache

# package.json scripts
{
  "scripts": {
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "lint:cache": "eslint src/ --cache"
  }
}

💡 İpucu: VS Code'da ESLint extension'ı yükle — dosya kaydedildiğinde otomatik düzeltme yapabilir. Settings: "editor.codeActionsOnSave": { "source.fixAll.eslint": "always" }

Inline Kuralları Kapatma/Açma

Bazen belirli satırlarda kuralı geçici olarak kapatman gerekir. Ama bunu bilinçli ve açıklamalı yap:

// Tek satır için kapat
// eslint-disable-next-line no-console
console.log("Bu bir debug mesajı");

// Belirli kural için kapat (açıklamalı — best practice)
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Legacy API tipsiz
const data: any = legacyApi.getData();

// Blok için kapat
/* eslint-disable no-console */
console.log("log 1");
console.log("log 2");
console.log("log 3");
/* eslint-enable no-console */

// Dosyanın tamamı için (dosyanın en üstünde)
/* eslint-disable @typescript-eslint/no-explicit-any */
// Bu dosya legacy API wrapper — any kullanımı kaçınılmaz

⚠️ Dikkat: eslint-disable kullanımını minimumda tut. Eğer bir projede çok fazla disable varsa, kuralı ya düzelt ya da kaldır. Disable, "bu kuralı biliyorum ama bilinçli olarak ihlal ediyorum" demektir — sürekli kullanılmamalıdır.


Prettier: Kod Formatlayıcı

ESLint hataları tespit eder ama formatlamaya sınırlı müdahale eder. Prettier ise kodun görünümünü tamamen düzeltir: girintileme, tırnak stili, satır uzunluğu, noktalı virgül, parantez konumu... Tüm format kararlarını alır, tartışmaya son verir.

Bir terzi gibi düşün: kumaşı (kodu) alır, düzgünce ütüler, temiz katlar — içeriğine dokunmaz, sadece görünümünü düzeltir.

Prettier'ın Felsefesi: Opinionated

Prettier'ın ayırt edici özelliği opinionated (fikirli/katı) olmasıdır. Çok az yapılandırma seçeneği sunar. Bu bir dezavantaj değil, en büyük avantajı:

ESLint: 200+ format kuralı, her biri tartışılabilir
→ Ekip: "Tab mı space mi?" "2 mi 4 mü?" tartışması

Prettier: ~10 ayar seçeneği, geri kalan sabit
→ Ekip: "Prettier ne diyorsa o." tartışma bitti ✅

Kurulum

npm install -D prettier

# ESLint ile çakışmaları engelle
npm install -D eslint-config-prettier

Yapılandırma

// .prettierrc
{
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 100,
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf"
}

Her ayarın anlamı:

semi: true           → Satır sonunda noktalı virgül (;) koy
singleQuote: false   → Çift tırnak kullan ("hello")
tabWidth: 2          → 2 boşluk girintileme
trailingComma: "all" → Son elemandan sonra da virgül koy
printWidth: 100      → Satır uzunluğu limiti (100 karakter)
bracketSpacing: true → Nesne literallerinde boşluk ({ a: 1 })
arrowParens: "always"→ Arrow function tek parametrede de parantez: (x) => x
endOfLine: "lf"      → Unix satır sonu (\n)
// .prettierignore
dist/
node_modules/
coverage/
*.min.js
pnpm-lock.yaml

Prettier Öncesi/Sonrası

// ❌ Önce: Tutarsız format
const user={name:"Ali",age:25,
  email:  'ali@test.com',
      preferences: {theme: 'dark',language:"tr"
  }
}

function greet(name){
  if(name) {return `Merhaba ${name}`}
  else{
return "Merhaba Misafir"
  }
}

// ✅ Sonra (Prettier uygulandıktan sonra): Tutarlı format
const user = {
  name: "Ali",
  age: 25,
  email: "ali@test.com",
  preferences: { theme: "dark", language: "tr" },
};

function greet(name) {
  if (name) {
    return `Merhaba ${name}`;
  } else {
    return "Merhaba Misafir";
  }
}

Prettier Çalıştırma

# Kontrol et (değiştirmeden)
npx prettier --check src/

# Düzelt
npx prettier --write src/

# Tek dosya
npx prettier --write src/utils/math.ts

# Belirli dosya türleri
npx prettier --write "src/**/*.{ts,tsx,css,json}"

ESLint + Prettier Entegrasyonu

ESLint ve Prettier'ın çakışan kuralları olabilir. eslint-config-prettier bu çakışmaları engeller:

// eslint.config.js — Prettier entegrasyonu
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import prettier from "eslint-config-prettier";

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,

  // ⚠️ Prettier'ı EN SONA koy — çakışan ESLint kurallarını kapatır
  prettier,

  {
    rules: {
      // Format kurallarını ESLint'te TANIMLA — Prettier halledecek
      // "semi": ... ← BUNU YAPMA
      // "quotes": ... ← BUNU YAPMA

      // Sadece mantık kurallarını ESLint'te tanımla
      "eqeqeq": "error",
      "no-var": "error",
      "prefer-const": "error",
    },
  }
);

Kural: ESLint = mantık ve kalite kuralları. Prettier = format kuralları. İkisini karıştırma.

💡 İpucu: Eski projelerde eslint-plugin-prettier kullanıldığını görebilirsin — bu, Prettier'ı ESLint kuralı olarak çalıştırır. Artık önerilmiyor. Modern yaklaşım: ESLint ve Prettier'ı ayrı ayrı çalıştır, eslint-config-prettier ile çakışmaları engelle.


Husky + lint-staged: Commit Öncesi Kalkan

ESLint ve Prettier harika araçlar ama kullanılmadıkça işe yaramazlar. Geliştirici eslint veya prettier çalıştırmayı unutabilir. Sonuç: hatalı, formatlanmamış kod repo'ya girer.

Çözüm: Git hook'ları ile commit öncesi otomatik kontrol. Kapıdaki güvenlik noktası gibi — çıkmadan önce kontrol yapılır.

Git Hook'ları Nedir?

Git, belirli olaylarda (commit, push, merge) otomatik script çalıştırabilir. Bu scriptlere hook denir:

pre-commit    → Commit ÖNCESI çalışır (lint, format, test)
commit-msg    → Commit mesajını KONTROL eder
pre-push      → Push ÖNCESI çalışır (testler)
post-merge    → Merge SONRASI çalışır (npm install)

Husky: Git Hook Yöneticisi

# Husky kurulumu
npm install -D husky

# Git hooks klasörünü oluştur
npx husky init

Bu komut .husky/pre-commit dosyası oluşturur. Her git commit komutu çalıştırılmadan önce bu script çalışır.

lint-staged: Sadece Değişen Dosyaları Kontrol Et

Tüm projeyi her commit'te kontrol etmek yavaş. lint-staged sadece staging area'daki (commit edilecek) dosyaları kontrol eder:

npm install -D lint-staged
// package.json
{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ]
  }
}
# .husky/pre-commit
npx lint-staged

Akış

git add src/math.ts     ← Dosya staging'e eklendi
git commit -m "fix"     ← Commit denemesi
  ↓
Husky: pre-commit hook tetiklendi
  ↓
lint-staged: sadece math.ts için:
  1. eslint --fix math.ts  ← Lint hatası varsa commit durur!
  2. prettier --write math.ts ← Format düzeltilir
  ↓
Hata yoksa: Commit başarılı ✅
Hata varsa: Commit engellendi ❌ (geliştirici düzeltmeli)
# Örnek senaryo
$ git commit -m "kullanıcı validasyonu eklendi"

⧗ Preparing lint-staged...
❯ Running tasks for *.{ts,tsx,js,jsx}...
  ✖ eslint --fix:
    /src/userValidator.ts
      3:7  error  'unused' is assigned but never used  @typescript-eslint/no-unused-vars
      7:5  error  Unexpected 'var', use 'let' or 'const'  no-var

✖ lint-staged failed! Fix the errors and try again.

Geliştirici hataları düzeltmeden commit yapamaz. Bu sayede repo'ya hatalı kod girmez.

commitlint: Commit Mesajı Standardı

npm install -D @commitlint/cli @commitlint/config-conventional
// commitlint.config.js
export default {
  extends: ["@commitlint/config-conventional"],
};

// Geçerli commit mesajları:
// feat: kullanıcı kaydı eklendi
// fix: login hatası düzeltildi
// docs: README güncellendi
// style: format düzeltmesi
// refactor: UserService yeniden yapılandırıldı
// test: cart testleri eklendi
// chore: dependencies güncellendi
# .husky/commit-msg
npx --no -- commitlint --edit ${1}
# ❌ Kötü commit mesajı → engellenir
$ git commit -m "fix"
⧗   input: fix
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

# ✅ İyi commit mesajı → kabul edilir
$ git commit -m "fix: login sayfasında şifre validasyonu düzeltildi"

Conventional Commits Tipleri

feat:     → Yeni özellik
fix:      → Hata düzeltmesi
docs:     → Dokümantasyon değişikliği
style:    → Format değişikliği (boşluk, noktalı virgül)
refactor: → Kod yeniden yapılandırma (özellik/hata değişikliği yok)
test:     → Test ekleme/düzeltme
chore:    → Build, CI, dependency gibi bakım işleri
perf:     → Performans iyileştirmesi
ci:       → CI/CD pipeline değişikliği

Scope ekleyebilirsin:
feat(auth): Google OAuth eklendi
fix(cart): ürün silme hatası düzeltildi
refactor(api): fetch client abstraction

CI/CD Entegrasyonu

Husky yerel geliştirme ortamında çalışır. Ama biri --no-verify ile commit'i bypass edebilir. CI/CD pipeline'ı son savunma hattıdır:

GitHub Actions Örneği

# .github/workflows/quality.yml
name: Code Quality

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: "npm"

      - run: npm ci              # Lock dosyasına sadık kur

      - run: npm run lint         # ESLint kontrolü
      
      - run: npx prettier --check src/  # Format kontrolü
      
      - run: npm run type-check   # TypeScript tip kontrolü (tsc --noEmit)
      
      - run: npm test            # Testler

Bu pipeline sayesinde:

  • PR açıldığında otomatik kontrol

  • Lint hatası varsa merge engellenebilir

  • Tüm ekip aynı standartlara uymak zorunda

💡 İpucu: GitHub'da branch protection rules ile "Required status checks" ayarlayarak, bu CI kontrollerini geçmeden merge'i engelleyebilirsin. Bu, kalite kontrol zincirinin en güçlü halkası.


Editor Entegrasyonu

VS Code Ayarları

// .vscode/settings.json — Proje seviyesinde
{
  // Kayıt sırasında format
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",

  // ESLint otomatik düzeltme
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "always",
    "source.organizeImports": "always"
  },

  // Dosya türüne göre formatter
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[markdown]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },

  // TypeScript ayarları
  "typescript.preferences.importModuleSpecifier": "relative",
  "typescript.updateImportsOnFileMove.enabled": "always"
}
// .vscode/extensions.json — Önerilen extension'lar
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "streetsidesoftware.code-spell-checker",
    "usernamehw.errorlens",
    "gruntfuggly.todo-tree"
  ]
}

EditorConfig: Editörler Arası Uyum

Prettier kullansan bile, VS Code dışında editör kullanan ekip üyeleri için .editorconfig faydalıdır:

# .editorconfig
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab

Sıfırdan Tam Kurulum Rehberi

Yeni bir projeye tüm kalite araçlarını kurmak için adım adım:

# 1. Proje oluştur
mkdir my-project && cd my-project
npm init -y

# 2. TypeScript
npm install -D typescript
npx tsc --init

# 3. ESLint + TypeScript
npm install -D eslint @eslint/js typescript-eslint eslint-config-prettier

# 4. Prettier
npm install -D prettier

# 5. Husky + lint-staged + commitlint
npm install -D husky lint-staged
npm install -D @commitlint/cli @commitlint/config-conventional
npx husky init

# 6. Yapılandır
echo 'npx lint-staged' > .husky/pre-commit
echo 'npx --no -- commitlint --edit ${1}' > .husky/commit-msg
// package.json — eklenecek scripts ve lint-staged
{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "format": "prettier --write src/",
    "format:check": "prettier --check src/",
    "type-check": "tsc --noEmit",
    "quality": "npm run lint && npm run format:check && npm run type-check",
    "test": "jest"
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css}": ["prettier --write"]
  }
}

Oluşturulacak yapılandırma dosyaları:

my-project/
├── eslint.config.js        ← ESLint flat config
├── .prettierrc             ← Prettier ayarları
├── .prettierignore         ← Prettier yoksayma
├── .editorconfig           ← Editör ayarları
├── commitlint.config.js    ← Commit mesajı kuralları
├── tsconfig.json           ← TypeScript ayarları
├── .vscode/
│   ├── settings.json       ← VS Code proje ayarları
│   └── extensions.json     ← Önerilen extension'lar
├── .husky/
│   ├── pre-commit          ← npx lint-staged
│   └── commit-msg          ← commitlint
└── src/
    └── index.ts

Gerçek Dünya: Kalite Kontrol Katmanları

Her şey kurulduktan sonra günlük iş akışı şöyle olur:

Katman 1: YAZARKEN
├── VS Code ESLint extension → Anında kırmızı/sarı altı çizili
├── VS Code Prettier → Kayıt sırasında otomatik format
└── TypeScript → Tip hataları anında görünür

Katman 2: COMMIT EDERKEN
├── Husky pre-commit hook tetiklenir
├── lint-staged: değişen dosyalarda ESLint + Prettier çalışır
├── commitlint: commit mesajı formatını kontrol eder
└── Hata varsa commit engellenir

Katman 3: PUSH/PR SIRASINDA
├── GitHub Actions / GitLab CI tetiklenir
├── Tüm dosyalarda lint, format, tip kontrolü çalışır
├── Testler çalışır
└── Başarısızsa merge engellenir

Katman 4: PRODUCTION
├── Build sırasında TypeScript derleme
├── Bundler optimizasyonları
└── Source map ile debug

Geliştirici perspektifinden neredeyse görünmez — arka planda çalışır, sadece hata yaptığında kendini gösterir. Bu zero-friction quality yaklaşımıdır.


Yaygın Hatalar

1. ESLint ve Prettier Çakışması

// ❌ ESLint'te format kuralı + Prettier = çatışma
// ESLint: "tek tırnak kullan" vs Prettier: "çift tırnak kullan"
// Sonuç: Her kayıtta dosya değişir, ESLint hata verir, Prettier düzeltir...

// ✅ Çözüm: eslint-config-prettier kullan — ESLint format kurallarını kapatır
// ESLint: mantık kuralları (eqeqeq, no-var, no-unused-vars)
// Prettier: format kuralları (quotes, semi, indentation)

2. lint-staged Olmadan Husky Kullanmak

# ❌ Tüm projeyi kontrol eder — yavaş!
# .husky/pre-commit
npx eslint src/

# ✅ Sadece değişen dosyaları kontrol et — hızlı!
# .husky/pre-commit
npx lint-staged

3. ESLint Kurallarını Devre Dışı Bırakma Alışkanlığı

// ❌ Her yerde disable — kuralın anlamı kalmıyor
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = fetchSomething();

// ✅ Gerçekten gerekiyorsa, nedenini açıkla
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 3rd party API untyped
const data: any = legacyApi.getData();

4. Prettier'ı Yanlış Yere Koymak

// ❌ eslint.config.js'de prettier EN SONA konmalı
export default tseslint.config(
  prettier,  // ❌ Başta — etkisiz!
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
);

// ✅ Doğru sıralama
export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  prettier,  // ✅ En sonda — format kurallarını override eder
);

5. CI'da npm ci Yerine npm install Kullanmak

# ❌ CI/CD'de npm install — lock dosyası güncellenebilir
npm install && npm run lint

# ✅ CI/CD'de npm ci — lock dosyasına sadık kalır
npm ci && npm run lint

Özel ESLint Kuralı Yazma (İleri Seviye)

Projeye özel kurallar yazabilirsin. Örneğin, console.log yerine özel logger kullanmayı zorunlu kılan bir kural:

// eslint-rules/no-direct-console.js
export default {
  meta: {
    type: "suggestion",
    docs: {
      description: "console.log yerine Logger kullanımını zorla",
    },
    fixable: "code",
    messages: {
      useLogger: "console.{{ method }} yerine Logger.{{ method }} kullanın",
    },
  },
  create(context) {
    return {
      MemberExpression(node) {
        if (
          node.object.name === "console" &&
          ["log", "warn", "error", "info"].includes(node.property.name)
        ) {
          context.report({
            node,
            messageId: "useLogger",
            data: { method: node.property.name },
            fix(fixer) {
              return fixer.replaceText(node.object, "Logger");
            },
          });
        }
      },
    };
  },
};

// eslint.config.js'de kullanım:
import noDirectConsole from "./eslint-rules/no-direct-console.js";

export default [
  {
    plugins: {
      custom: { rules: { "no-direct-console": noDirectConsole } },
    },
    rules: {
      "custom/no-direct-console": "error",
    },
  },
];

Özet

  • ESLint: Kod kalitesi ve mantık hatalarını tespit eder. === kullanımı, unused vars, any tipi gibi sorunları yakalar. ESLint 9+ flat config formatını kullan.

  • Prettier: Kod formatını otomatik düzeltir. Tab/space, tırnak, noktalı virgül tartışmalarına son verir. Opinionated — az seçenek, tutarlı sonuç.

  • ESLint + Prettier: ESLint mantık kuralları, Prettier format kuralları. eslint-config-prettier ile çakışmayı engelle. Prettier her zaman config'in sonunda olmalı.

  • Husky: Git hook'larını yönetir. pre-commit hook'u ile commit öncesi kontrol. commit-msg hook'u ile commit mesajı standardı.

  • lint-staged: Sadece commit edilecek dosyaları kontrol eder — hızlı ve odaklı. Tüm projeyi kontrol etmekten kaçın.

  • CI/CD: GitHub Actions veya GitLab CI ile push/PR'da otomatik kontrol. npm ci ile tutarlı kurulum.

  • Editor entegrasyonu: VS Code'da kayıt sırasında otomatik format ve lint fix — sıfır sürtünme.

  • Tüm bu araçlar birlikte: yazmadan önce, yazarken, commit ederken ve CI'da — dört katmanlı kalite koruması sağlar.