Developer Tools

ESLint & Prettier: Code Quality

Tutorial lengkap menjaga kualitas kode dengan ESLint dan Prettier β€” konfigurasi rules, plugins, integrasi VS Code, auto-fix, pre-commit hooks, dan CI/CD pipeline

1. Pengenalan Code Quality Tools

Saat bekerja dalam tim pengembangan software, menjaga kualitas dan konsistensi kode adalah hal yang sangat penting. Tanpa tools yang tepat, setiap developer bisa memiliki gaya penulisan yang berbeda β€” ada yang menggunakan tab, ada yang spasi; ada yang pakai titik koma, ada yang tidak.

Dua tools yang menjadi standar industri untuk menjaga kualitas kode JavaScript/TypeScript adalah ESLint dan Prettier:

ESLint vs Prettier: Apa Bedanya?

Aspek ESLint Prettier
Fungsi UtamaMenemukan dan memperbaiki masalah kode (bugs, patterns, best practices)Memformat tampilan kode (indentasi, spasi, line breaks)
Tipe MasalahLogic errors, unused variables, no-undef, no-console, security issuesCode style: indentation, trailing commas, semicolons, quotes, line width
CustomisasiSangat fleksibel β€” ratusan rules yang bisa diaturOpsi terbatas β€” sengaja dibuat opinionated
Auto-fixBisa untuk sebagian rulesBisa untuk semua formatting
AnalogiSeperti pemeriksa tata bahasa (grammar checker)Seperti formatter dokumen (auto-format)
Diagram: Workflow Code Quality
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              CODE QUALITY WORKFLOW                       β”‚
β”‚                                                         β”‚
β”‚  Developer Menulis Kode                                 β”‚
β”‚         β”‚                                               β”‚
β”‚         β–Ό                                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  VS Code Extension β”‚  ← Real-time feedback          β”‚
β”‚  β”‚  (ESLint + Prettier)β”‚  ← Format on save             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚           β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  Pre-commit Hook   β”‚  ← Husky + lint-staged         β”‚
β”‚  β”‚  (git commit)      β”‚  ← Auto-fix sebelum commit     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚           β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  CI/CD Pipeline    β”‚  ← GitHub Actions / GitLab CI  β”‚
β”‚  β”‚  (Push to remote)  β”‚  ← Block merge jika gagal      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚           β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  Code Review       β”‚  ← PR quality sudah terjaga    β”‚
β”‚  β”‚  (Pull Request)    β”‚  ← Reviewer fokus ke logic     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. ESLint: Dasar dan Instalasi

ESLint adalah static analysis tool yang secara otomatis mendeteksi masalah dalam kode JavaScript dan TypeScript. ESLint pertama kali dibuat oleh Nicholas C. Zakas pada tahun 2013 dan sekarang menjadi tool linting yang paling banyak digunakan di ekosistem JavaScript.

Instalasi

bash
# Inisialisasi ESLint di proyek baru
npm init @eslint@latest

# Wizard akan menanyakan:
# βœ” How would you like to use ESLint? β†’ To check syntax and find problems
# βœ” What type of modules does your project use? β†’ ES Modules
# βœ” Which framework does your project use? β†’ React / None
# βœ” Does your project use TypeScript? β†’ Yes / No
# βœ” Where does your code run? β†’ Browser / Node
# βœ” What format do you want your config file to be in? β†’ ESM (eslint.config.mjs)
# βœ” Would you like to install them now? β†’ Yes

# Atau instal manual:
npm install -D eslint @eslint/js

# Untuk TypeScript:
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin

# Untuk React:
npm install -D eslint-plugin-react eslint-plugin-react-hooks

Menjalankan ESLint

bash
# Lint satu file
npx eslint src/app.js

# Lint seluruh direktori
npx eslint src/

# Lint dengan pattern
npx eslint "src/**/*.{js,ts,jsx,tsx}"

# Auto-fix masalah yang bisa diperbaiki
npx eslint --fix src/

# Cek tanpa memperbaiki (untuk CI)
npx eslint src/ --no-fix

# Output format untuk CI tools
npx eslint src/ --format json
npx eslint src/ --format junit

3. Konfigurasi ESLint (Flat Config)

ESLint v9+ menggunakan format flat config (eslint.config.mjs) yang menggantikan format lama .eslintrc. Flat config menggunakan JavaScript biasa sehingga lebih fleksibel dan mudah dipahami.

javascript
// eslint.config.mjs β€” Konfigurasi ESLint modern (v9+)
import js from '@eslint/js';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';

export default [
  // === Global ignores ===
  {
    ignores: ['dist/**', 'build/**', 'node_modules/**', '*.min.js', 'coverage/**']
  },

  // === Base config untuk semua file ===
  js.configs.recommended,

  // === TypeScript config ===
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
        ecmaFeatures: { jsx: true },
        project: './tsconfig.json'
      }
    },
    plugins: {
      '@typescript-eslint': tsPlugin
    },
    rules: {
      // TypeScript specific rules
      '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
      '@typescript-eslint/no-explicit-any': 'warn',
      '@typescript-eslint/explicit-function-return-type': 'off',
      '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
      '@typescript-eslint/no-non-null-assertion': 'warn',
      '@typescript-eslint/no-floating-promises': 'error',
      '@typescript-eslint/await-thenable': 'error'
    }
  },

  // === React config ===
  {
    files: ['**/*.{jsx,tsx}'],
    plugins: {
      'react': reactPlugin,
      'react-hooks': reactHooksPlugin
    },
    settings: {
      react: { version: 'detect' }
    },
    rules: {
      'react/react-in-jsx-scope': 'off',         // React 17+ tidak perlu import React
      'react/prop-types': 'off',                   // Gunakan TypeScript
      'react/jsx-uses-react': 'off',
      'react/jsx-uses-vars': 'error',
      'react/self-closing-comp': 'error',
      'react/jsx-no-duplicate-props': 'error',
      'react/jsx-key': 'error',
      'react/no-array-index-key': 'warn',
      'react/no-danger': 'warn',
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn'
    }
  },

  // === Custom rules untuk proyek ===
  {
    rules: {
      // Best practices
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-debugger': 'error',
      'no-alert': 'error',
      'no-var': 'error',
      'prefer-const': 'error',
      'prefer-template': 'error',
      'no-duplicate-imports': 'error',
      'eqeqeq': ['error', 'always'],
      'curly': ['error', 'multi-line'],

      // Style (yang tidak ditangani Prettier)
      'no-multiple-empty-lines': ['error', { max: 1 }],
      'no-trailing-spaces': 'error',
      'padding-line-between-statements': [
        'error',
        { blankLine: 'always', prev: '*', next: 'return' }
      ]
    }
  }
];

4. Memahami Rules ESLint

Setiap rule ESLint memiliki tiga level severity:

Level Angka Arti Dampak di CI
"off" / 00Rule dimatikanTidak ada
"warn" / 11Peringatan (warning)CI tetap pass, tapi ada warning
"error" / 22Error β€” harus diperbaikiCI gagal

Contoh Rule dengan Opsi

javascript
// eslint.config.mjs β€” Contoh rules dengan opsi detail
{
  rules: {
    // === Error Prevention ===
    'no-unused-vars': 'off',  // Gunakan @typescript-eslint version
    '@typescript-eslint/no-unused-vars': [
      'error',
      {
        argsIgnorePattern: '^_',          // _arg diabaikan
        varsIgnorePattern: '^_',          // _var diabaikan
        caughtErrorsIgnorePattern: '^_',  // catch (_err)
        destructuredArrayIgnorePattern: '^_'
      }
    ],

    // === Best Practices ===
    'no-var': 'error',                    // Gunakan let/const
    'prefer-const': 'error',              // Gunakan const jika tidak berubah
    'prefer-template': 'warn',            // Gunakan template literal
    'no-implicit-coercion': 'error',      // Hindari !!, +, '' untuk konversi
    'no-return-await': 'error',           // Hindari return await yang tidak perlu
    'require-await': 'warn',              // async function harus punya await
    'no-throw-literal': 'error',          // throw new Error(), bukan throw "msg"

    // === Security ===
    'no-eval': 'error',                   // Larang eval()
    'no-implied-eval': 'error',           // Larang setTimeout("code")
    'no-new-func': 'error',               // Larang new Function()

    // === Code Consistency ===
    'arrow-body-style': ['error', 'as-needed'],
    'object-shorthand': ['error', 'always'],
    'prefer-destructuring': ['warn', {
      array: false,
      object: true
    }],
    'no-nested-ternary': 'warn',          // Hindari ternary bersarang
    'max-depth': ['warn', 3],             // Max nesting depth
    'max-lines-per-function': ['warn', {
      max: 100,
      skipBlankLines: true,
      skipComments: true
    }]
  }
}

Contoh Kode yang Melanggar Rules

javascript
// ❌ Kode yang melanggar rules
var name = "Budi";                    // Error: no-var
const unused = 10;                    // Error: no-unused-vars
if (value == true) { }                // Error: eqeqeq (harus ===)
console.log("debug");                 // Warn: no-console
const result = "" + value;            // Error: no-implicit-coercion
const name2 = "Hello " + name;        // Warn: prefer-template

// βœ… Kode yang sudah diperbaiki
const name = "Budi";                  // const, bukan var
// (hapus unused variable)
if (value === true) { }              // === bukan ==
console.error("error message");      // console.error diizinkan
const result = String(value);         // eksplisit konversi
const greeting = `Hello ${name}`;     // template literal

5. Plugin Populer ESLint

Plugin Kegunaan Instalasi
eslint-plugin-reactRules khusus untuk Reactnpm i -D eslint-plugin-react
eslint-plugin-react-hooksRules untuk React Hooksnpm i -D eslint-plugin-react-hooks
eslint-plugin-vueRules untuk Vue.jsnpm i -D eslint-plugin-vue
eslint-plugin-importRules untuk import/export statementsnpm i -D eslint-plugin-import
eslint-plugin-tailwindcssRules untuk Tailwind CSS classnpm i -D eslint-plugin-tailwindcss
eslint-plugin-securityDeteksi security issuesnpm i -D eslint-plugin-security
eslint-plugin-sonarjsDeteksi code smells dan bugsnpm i -D eslint-plugin-sonarjs
eslint-plugin-jestRules untuk Jest testingnpm i -D eslint-plugin-jest
eslint-plugin-perfDeteksi pola kode yang lambatnpm i -D eslint-plugin-perf
@eslint/jsRekomendasi rules dasar ESLintnpm i -D @eslint/js

6. Prettier: Dasar dan Instalasi

Prettier adalah opinionated code formatter yang mendukung banyak bahasa: JavaScript, TypeScript, HTML, CSS, JSON, Markdown, YAML, GraphQL, dan lainnya. Prettier memastikan semua kode di proyek memiliki format yang konsisten β€” tidak peduli siapa yang menulisnya.

Instalasi

bash
# Instal Prettier
npm install -D prettier

# Buat file konfigurasi
echo {} > .prettierrc.json

# Buat file ignore
echo "node_modules
dist
build
coverage" > .prettignore

Menjalankan Prettier

bash
# Format satu file
npx prettier --write src/app.ts

# Format seluruh direktori
npx prettier --write "src/**/*.{js,ts,jsx,tsx,json,css,md}"

# Cek format tanpa memperbaiki (untuk CI)
npx prettier --check "src/**/*.{js,ts,jsx,tsx}"

# Format semua file di proyek
npx prettier --write .

# Format dan lihat diff
npx prettier --write --list-different src/

7. Konfigurasi Prettier

json
// .prettierrc.json β€” Konfigurasi Prettier
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false,
  "trailingComma": "all",
  "printWidth": 100,
  "bracketSpacing": true,
  "bracketSameLine": false,
  "arrowParens": "always",
  "endOfLine": "lf",
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "htmlWhitespaceSensitivity": "css",
  "proseWrap": "preserve",
  "embeddedLanguageFormatting": "auto"
}

Penjelasan Opsi Penting

Opsi Default Penjelasan
semitrueTambahkan titik koma di akhir statement
singleQuotefalseGunakan single quote alih-alih double quote
tabWidth2Jumlah spasi per indentasi
trailingComma"all"Tambahkan koma di akhir array/object/function params
printWidth80Lebar maksimal baris sebelum Prettier memecah baris
bracketSpacingtrueTambahkan spasi di dalam kurung objek: { a: 1 }
arrowParens"always"Selalu gunakan kurung pada arrow function params

Contoh Hasil Format Prettier

javascript
// ❌ SEBELUM di-format Prettier:
const user={name:"Budi",age:25,email:"budi@mail.com",isActive:true,skills:["JavaScript","TypeScript","React","Node.js"]}
const greeting = "Hello " + user.name + "! Welcome to " + "our platform. We hope you enjoy your stay here with us."
function calculateTotal(items){let total=0;for(let i=0;i<items.length;i++){total+=items[i].price*items[i].quantity}return total}

// βœ… SESUDAH di-format Prettier:
const user = {
  name: 'Budi',
  age: 25,
  email: 'budi@mail.com',
  isActive: true,
  skills: ['JavaScript', 'TypeScript', 'React', 'Node.js'],
};

const greeting =
  "Hello " + user.name + "! Welcome to " +
  "our platform. We hope you enjoy your stay here with us.";

function calculateTotal(items) {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total += items[i].price * items[i].quantity;
  }
  return total;
}

8. Mengintegrasikan ESLint + Prettier

ESLint dan Prettier memiliki beberapa rules yang overlap (misalnya tentang semicolons, quotes, indentation). Tanpa integrasi yang benar, keduanya bisa saling konflik. Solusinya: gunakan eslint-config-prettier untuk mematikan rules ESLint yang konflik dengan Prettier.

Instalasi

bash
# Matikan ESLint rules yang konflik dengan Prettier
npm install -D eslint-config-prettier

# (Opsional) Jalankan Prettier sebagai ESLint rule
# NOTE: Banyak yang TIDAK merekomendasikan ini karena lambat
# Lebih baik jalankan Prettier terpisah
npm install -D eslint-plugin-prettier

Konfigurasi Terintegrasi

javascript
// eslint.config.mjs β€” ESLint + Prettier terintegrasi
import js from '@eslint/js';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import prettierConfig from 'eslint-config-prettier';

export default [
  js.configs.recommended,

  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
        project: './tsconfig.json'
      }
    },
    plugins: {
      '@typescript-eslint': tsPlugin
    },
    rules: {
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/no-explicit-any': 'warn',
    }
  },

  // HARUS di akhir β€” mematikan rules yang konflik dengan Prettier
  prettierConfig,

  {
    ignores: ['dist/**', 'node_modules/**']
  }
];

npm Scripts yang Direkomendasikan

json
// package.json
{
  "scripts": {
    "lint": "eslint \"src/**/*.{js,ts,jsx,tsx}\"",
    "lint:fix": "eslint --fix \"src/**/*.{js,ts,jsx,tsx}\"",
    "format": "prettier --write \"src/**/*.{js,ts,jsx,tsx,json,css,md}\"",
    "format:check": "prettier --check \"src/**/*.{js,ts,jsx,tsx,json,css,md}\"",
    "check": "npm run lint && npm run format:check",
    "fix": "npm run lint:fix && npm run format"
  }
}

9. Integrasi dengan VS Code

Untuk pengalaman development yang optimal, konfigurasikan VS Code agar ESLint dan Prettier berjalan otomatis saat kamu menulis kode.

Extensions yang Dibutuhkan

VS Code Settings

json
// .vscode/settings.json β€” VS Code workspace settings
{
  // === Prettier sebagai default formatter ===
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": false,

  // === ESLint auto-fix on save ===
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "explicit"
  },

  // === Language-specific settings ===
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[css]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[markdown]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.wordWrap": "on"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },

  // === ESLint validation ===
  "eslint.validate": [
    "javascript",
    "typescript",
    "javascriptreact",
    "typescriptreact"
  ],

  // === Tambahan ===
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "files.eol": "\n",
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,

  // === Exclude dari file explorer ===
  "files.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.git": true
  }
}

Rekomendasi Extensions (workspace)

json
// .vscode/extensions.json β€” Rekomendasikan extensions ke tim
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "EditorConfig.EditorConfig",
    "bradlc.vscode-tailwindcss",
    "csstools.postcss",
    "christian-kohler.path-intellisense",
    "streetsidesoftware.code-spell-checker"
  ]
}

10. Pre-commit Hooks dengan Husky

Husky dan lint-staged memungkinkan kita menjalankan ESLint dan Prettier secara otomatis sebelum setiap git commit. Ini memastikan tidak ada kode yang bermasalah yang masuk ke repository.

Instalasi Husky + lint-staged

bash
# Instal Husky
npm install -D husky

# Inisialisasi Husky (membuat folder .husky/)
npx husky init

# Instal lint-staged
npm install -D lint-staged

Konfigurasi

bash
# .husky/pre-commit β€” Script yang dijalankan sebelum commit
npx lint-staged
json
// package.json β€” Konfigurasi lint-staged
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,css,md,yml,yaml}": [
      "prettier --write"
    ]
  }
}

Alur Pre-commit

Diagram: Pre-commit Hook Flow
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              PRE-COMMIT HOOK FLOW                       β”‚
β”‚                                                         β”‚
β”‚  Developer: git commit -m "feat: add product page"      β”‚
β”‚         β”‚                                               β”‚
β”‚         β–Ό                                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  Husky             β”‚  ← Intercept git hook           β”‚
β”‚  β”‚  .husky/pre-commit β”‚                                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚           β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  lint-staged       β”‚  ← Hanya file yang di-staged   β”‚
β”‚  β”‚                    β”‚                                 β”‚
β”‚  β”‚  *.ts, *.tsx:      β”‚                                 β”‚
β”‚  β”‚  1. eslint --fix   β”‚  ← Auto-fix masalah kode       β”‚
β”‚  β”‚  2. prettier --writeβ”‚  ← Auto-format                 β”‚
β”‚  β”‚                    β”‚                                 β”‚
β”‚  β”‚  *.json, *.css:    β”‚                                 β”‚
β”‚  β”‚  1. prettier --writeβ”‚  ← Format                     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚           β–Ό                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚  Result:            β”‚                                 β”‚
β”‚  β”‚  βœ… Pass β†’ Commit   β”‚                                 β”‚
β”‚  β”‚  ❌ Fail β†’ Block    β”‚  ← Developer harus fix dulu   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

11. CI/CD Integration

Mengintegrasikan ESLint dan Prettier ke dalam CI/CD pipeline memastikan bahwa setiap pull request yang masuk sudah memenuhi standar kualitas kode tim kamu.

GitHub Actions

yaml
# .github/workflows/lint.yml
name: Code Quality

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

jobs:
  lint-and-format:
    name: Lint & Format Check
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Check Prettier formatting
        run: npm run format:check

      - name: Run TypeScript type check
        run: npx tsc --noEmit

  test:
    name: Unit Tests
    runs-on: ubuntu-latest
    needs: lint-and-format

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test -- --coverage

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage/lcov.info

GitLab CI

yaml
# .gitlab-ci.yml
stages:
  - quality
  - test

lint:
  stage: quality
  image: node:20
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint
    - npm run format:check
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_COMMIT_BRANCH == "develop"

typecheck:
  stage: quality
  image: node:20
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npx tsc --noEmit

test:
  stage: test
  image: node:20
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm test -- --coverage
  coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

12. Best Practices dan Cheat Sheet

Best Practices

Praktik Penjelasan
Gunakan Flat ConfigESLint v9+ menggunakan eslint.config.mjs β€” lebih fleksibel dan modern
Pisahkan ESLint dan PrettierESLint untuk logic, Prettier untuk format. Gunakan eslint-config-prettier
Commit Config ke RepoSimpan .prettierrc dan eslint.config.mjs di repo agar semua developer konsisten
Gunakan lint-stagedHanya lint file yang di-stage β€” lebih cepat dari linting seluruh proyek
Fail CI on ErrorsPastikan CI pipeline gagal jika ada ESLint error atau format yang salah
Mulai dari StrictLebih baik mulai ketat dan rilekskan rules daripada sebaliknya
Dokumentasikan Rule CustomBeri komentar mengapa setiap rule diatur β€” bantu tim memahami
Review Rules BerkalaEvaluasi rules setiap beberapa bulan β€” sesuaikan dengan kebutuhan tim

Cheat Sheet Perintah

bash
# ================================
# ESLINT CHEAT SHEET
# ================================

# Lint file
npx eslint src/app.ts

# Auto-fix
npx eslint --fix src/app.ts

# Lint dengan debug info
npx eslint --debug src/app.ts

# Inisialisasi ESLint baru
npm init @eslint@latest

# ================================
# PRETTIER CHEAT SHEET
# ================================

# Format file
npx prettier --write src/app.ts

# Cek format (CI)
npx prettier --check "src/**/*.{ts,tsx}"

# Format semua
npx prettier --write .

# Override config via CLI
npx prettier --single-quote --tab-width 4 --write src/app.ts

# ================================
# GABUNGAN
# ================================

# Fix everything (ESLint + Prettier)
npm run lint:fix && npm run format

# Check everything (CI)
npm run lint && npm run format:check

# Type check
npx tsc --noEmit

# Semua sekaligus
npm run lint && npm run format:check && npx tsc --noEmit

13. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang ESLint dan Prettier:

Pertanyaan 1: Apa fungsi utama ESLint?

a) Memformat kode agar rapi
b) Menemukan dan memperbaiki masalah kode (bugs, best practices)
c) Mengkompilasi TypeScript ke JavaScript
d) Menjalankan unit tests

Pertanyaan 2: Apa fungsi dari eslint-config-prettier?

a) Menjalankan Prettier dari dalam ESLint
b) Mematikan ESLint rules yang konflik dengan Prettier
c) Menggabungkan semua rules ESLint dan Prettier
d) Menginstall Prettier secara otomatis

Pertanyaan 3: Apa keunggulan menggunakan lint-staged dibanding linting seluruh proyek?

a) Lebih akurat hasilnya
b) Hanya file yang di-stage yang di-lint, sehingga lebih cepat
c) Tidak perlu menginstall ESLint
d) Bisa menggantikan CI/CD pipeline

Pertanyaan 4: Berapa level severity yang tersedia di ESLint rules?

a) 2 level: on/off
b) 3 level: off (0), warn (1), error (2)
c) 4 level: off, warn, error, critical
d) 5 level: off, info, warn, error, fatal

Pertanyaan 5: Format konfigurasi apa yang digunakan ESLint v9+?

a) .eslintrc.json
b) .eslintrc.yml
c) eslint.config.mjs (flat config)
d) .eslint.js
πŸ” Zoom
100%
🎨 Tema