フロントエンドコード規約とエンジニアリング実践:ESLint + Prettier + Husky 完全セットアップ

前端工程

なぜチームにコード規約の自動化が必要か

2 つの実例です。

例 A:開発者 A は 2 スペースインデント、開発者 B は 4 スペース。コードレビューのたびに diff の 80% が空白と改行。レビュアーのエネルギーはフォーマットに消費され、ロジックの問題が見逃されます。

例 B:インターンがコードをプッシュし、npm run build はパス。main ブランチにマージした翌日、本番環境でエラー:「typo in variable name」。自動チェックがあれば、このコミットは pre-commit フックを通過できませんでした。

コード規約は「人を縛るルール」ではなく、「ツールで自動的に品質のベースラインを保証し、本当に価値のある判断に集中できるようにするもの」です。この記事は 3 つのチームでの実装経験に基づいています。


セットアップ後の効果

git add .
git commit -m "feat: ユーザーログイン機能を追加"

# Husky が pre-commit フックを自動起動
# → lint-staged がステージングファイルに ESLint --fix + Prettier --write を実行
# → commitlint がコミットメッセージ形式を検証
# → すべてパス → コミット成功

ESLint Flat Config:.eslintrc からの脱却

2024 年末、ESLint 9.x で Flat Config がデフォルトになり、古い .eslintrc.* は非推奨になりました。

Flat Config の基本構造

// eslint.config.mjs
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import globals from 'globals';

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

  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      },
      parserOptions: {
        project: './tsconfig.json',
      },
    },
  },

  {
    rules: {
      '@typescript-eslint/no-unused-vars': ['error', {
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_',
      }],
      '@typescript-eslint/no-explicit-any': 'warn',
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'prefer-const': 'error',
      'no-var': 'error',
      'eqeqeq': ['error', 'always'],
    },
  },

  {
    ignores: [
      'dist/**',
      'node_modules/**',
      '.next/**',
      'coverage/**',
    ],
  }
);

移行理由

旧形式 新形式 説明
.eslintrc.js / .eslintrc.json eslint.config.mjs 単一の統一ファイル
extends チェーン継承 tseslint.config() 合成 継承より関数合成
overrides + glob パターン 設定オブジェクトの files より直感的
プラグインを文字列名で指定 import pluginX from '...' ネイティブ ESM インポート

Prettier:フォーマットは専門ツールに任せる

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

ESLint と Prettier の共存:

// eslint.config.mjs
import prettier from 'eslint-config-prettier';

export default tseslint.config(
  // ... 前の設定
  prettier,  // 最後に配置し、競合する全ルールを上書き
);

Husky + lint-staged:コミット前に問題をブロック

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

--max-warnings=0 により、警告 1 件でもコミットがブロックされます。


commitlint:コミットメッセージ形式の統一

npm i -D @commitlint/cli @commitlint/config-conventional
// commitlint.config.mjs
export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat', 'fix', 'docs', 'style',
        'refactor', 'perf', 'test', 'chore',
        'ci', 'revert',
      ],
    ],
    'subject-case': [0],
  },
};

正しいコミット形式:

git commit -m "feat: ユーザー認証モジュールを追加"
git commit -m "fix: トークン更新の競合状態を修正"

CI パイプライン統合

# .github/workflows/lint.yml
name: Lint & Format Check

on:
  pull_request:
    branches: [main, develop]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: 依存関係のインストール
        run: npm ci
      - name: ESLint 実行
        run: npx eslint . --max-warnings=0
      - name: フォーマットチェック
        run: npx prettier --check "src/**/*.{ts,tsx,js,jsx,json,css}"
      - name: 型チェック
        run: npx tsc --noEmit

実際の移行経験

ステップ 1:フォーマットを先に、ルールは後で

# 1. まず Prettier でプロジェクト全体をフォーマット
npx prettier --write "src/**/*.{ts,tsx}"

# 2. フォーマット変更をコミット
git add .
git commit -m "style: Prettier で全ファイルをフォーマット"

# 3. ESLint ルールを段階的に有効化

ステップ 2:段階的な厳格化

// フェーズ 1:error レベルのみ
{
  rules: {
    '@typescript-eslint/no-explicit-any': 'warn',
    'no-console': 'off',
    '@typescript-eslint/no-unused-vars': 'error',
  },
}

よくある落とし穴

落とし穴 1:ESLint Flat Config と VS Code プラグインの非互換

{
  "eslint.useFlatConfig": true,
  "eslint.options": {
    "overrideConfigFile": "eslint.config.mjs"
  }
}

落とし穴 2:Windows と macOS の改行コード衝突

.prettierrc"endOfLine": "lf" を設定し、.gitattributes を追加:

* text=auto eol=lf

関連ツール

ブラウザローカルツールを無料で試す →

#ESLint#Prettier#代码规范#工程化#前端#教程