はじめに

ReactプロジェクトでLinter(ESLint)とFormatter(Prettier)を適切に設定することは、コード品質の維持とチーム開発の効率化に不可欠です。本記事では、2025年以降の最新ベストプラクティスに基づき、ESLintのFlat Config形式での設定方法、Prettierとの連携、CI/CD環境での活用まで包括的に解説します。

本記事を読むことで、以下のことができるようになります。

  • ESLintとPrettierの役割の違いを理解する
  • ReactプロジェクトにESLintをFlat Config形式で導入する
  • ESLintとPrettierを競合なく連携させる
  • Git HooksやCI/CDでLinter・Formatterを自動実行する
  • よくあるトラブルを解決する

実行環境・前提条件

必要な環境

  • Node.js:v18.18.0以上、v20.9.0以上、またはv21.1.0以上
  • npm:v9以上(またはyarn/pnpm)
  • エディタ:VS Code推奨

前提知識

  • Reactプロジェクトの基本構成
  • npmコマンドの基本操作
  • JavaScriptまたはTypeScriptの基礎知識

ESLintとPrettierの役割の違い

ESLintとPrettierは混同されやすいですが、それぞれ異なる目的を持っています。

ESLint(Linter)の役割

ESLintは静的解析ツールであり、コードの品質バグの可能性を検出します。

  • 未使用変数の検出
  • 未定義変数の使用検出
  • Reactフック(Hooks)のルール違反検出
  • セキュリティ上の問題検出
1
2
3
4
5
6
// ESLintが検出する問題の例
const unused = "この変数は使用されていません"; // no-unused-vars

if (condition = true) { // no-cond-assign(代入と比較の誤り)
  console.log("問題のあるコード");
}

Prettier(Formatter)の役割

Prettierはコードフォーマッターであり、コードの見た目を統一します。

  • インデントの統一
  • クォートスタイルの統一(シングル/ダブル)
  • セミコロンの有無
  • 行の折り返し
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Prettierが整形する例
// Before
const obj={name:"React",type:'library',version:18}

// After(Prettier適用後)
const obj = {
  name: "React",
  type: "library",
  version: 18,
};

なぜ両方必要なのか

ツール 目的 検出対象
ESLint 品質チェック バグ、ベストプラクティス違反
Prettier フォーマット コードスタイル、見た目

両者は補完関係にあり、ESLintで品質を担保し、Prettierで見た目を統一することで、可読性が高くバグの少ないコードベースを維持できます。

ESLintの導入とFlat Config設定

ESLint v9以降では、Flat Config(eslint.config.js)が標準の設定形式となっています。従来の.eslintrc.*形式からFlat Configへの移行が推奨されています。

ESLintのインストール

ReactプロジェクトにESLintをインストールします。Viteで作成したReactプロジェクトには、ESLintが既にセットアップされている場合があります。

1
2
3
4
5
6
7
8
# ESLintと関連パッケージのインストール
npm install -D eslint @eslint/js globals

# React用プラグインのインストール
npm install -D eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh

# TypeScriptを使用する場合は追加でインストール
npm install -D typescript-eslint

Flat Config形式の設定ファイル作成

プロジェクトルートにeslint.config.jsを作成します。

JavaScript + Reactの場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// eslint.config.js
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";

export default [
  // 無視するファイル・ディレクトリ
  { ignores: ["dist", "node_modules", "build"] },
  
  // JavaScript/JSXファイルの設定
  {
    files: ["**/*.{js,jsx}"],
    languageOptions: {
      ecmaVersion: 2024,
      globals: {
        ...globals.browser,
        ...globals.es2024,
      },
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      // ESLint推奨ルールを適用
      ...js.configs.recommended.rules,
      
      // React Hooks公式ルール
      ...reactHooks.configs.recommended.rules,
      
      // React Fast Refresh対応
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
      
      // 追加の推奨ルール
      "no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
      "no-console": ["warn", { allow: ["warn", "error"] }],
    },
  },
];

TypeScript + Reactの場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// eslint.config.js
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  // 無視するファイル・ディレクトリ
  { ignores: ["dist", "node_modules", "build", "*.config.js"] },
  
  // TypeScript/TSXファイルの設定
  {
    files: ["**/*.{ts,tsx}"],
    extends: [
      js.configs.recommended,
      ...tseslint.configs.recommended,
    ],
    languageOptions: {
      ecmaVersion: 2024,
      globals: {
        ...globals.browser,
        ...globals.es2024,
      },
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
        project: ["./tsconfig.json", "./tsconfig.node.json"],
      },
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      // React Hooks公式ルール
      ...reactHooks.configs.recommended.rules,
      
      // React Fast Refresh対応
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
      
      // TypeScript固有の推奨ルール
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_" },
      ],
      "@typescript-eslint/explicit-function-return-type": "off",
      "@typescript-eslint/no-explicit-any": "warn",
      
      // 一般的な推奨ルール
      "no-console": ["warn", { allow: ["warn", "error"] }],
    },
  },
);

package.jsonへのスクリプト追加

1
2
3
4
5
6
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

ESLintの実行

1
2
3
4
5
# リントチェックの実行
npm run lint

# 自動修正可能な問題を修正
npm run lint:fix

Prettierの導入と設定

Prettierのインストール

1
npm install -D prettier

Prettier設定ファイルの作成

プロジェクトルートに.prettierrcを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "semi": true,
  "singleQuote": false,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80,
  "bracketSpacing": true,
  "jsxSingleQuote": false,
  "arrowParens": "always",
  "endOfLine": "lf"
}

各オプションの説明は以下の通りです。

オプション 説明
semi true 文末にセミコロンを付与
singleQuote false ダブルクォートを使用
tabWidth 2 インデント幅
trailingComma "es5" ES5互換の末尾カンマ
printWidth 80 1行の最大文字数
bracketSpacing true オブジェクトリテラルの括弧内にスペース
jsxSingleQuote false JSXでダブルクォートを使用
arrowParens "always" アロー関数の引数を常に括弧で囲む
endOfLine "lf" 改行コードをLFに統一

.prettierignoreファイルの作成

フォーマット対象外のファイルを指定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# ビルド成果物
dist
build
.next

# 依存関係
node_modules

# ロックファイル
package-lock.json
yarn.lock
pnpm-lock.yaml

# 自動生成ファイル
*.min.js
*.min.css
coverage

package.jsonへのスクリプト追加

1
2
3
4
5
6
{
  "scripts": {
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

ESLintとPrettierの競合解消

ESLintにはコードスタイルに関するルールも含まれており、Prettierと競合する可能性があります。eslint-config-prettierを使用して、競合するルールを無効化します。

eslint-config-prettierのインストール

1
npm install -D eslint-config-prettier

ESLint設定への追加

eslint.config.js最後eslint-config-prettierを追加します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// eslint.config.js
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier/flat";

export default tseslint.config(
  { ignores: ["dist", "node_modules", "build"] },
  
  {
    files: ["**/*.{ts,tsx}"],
    extends: [
      js.configs.recommended,
      ...tseslint.configs.recommended,
    ],
    languageOptions: {
      ecmaVersion: 2024,
      globals: {
        ...globals.browser,
        ...globals.es2024,
      },
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_" },
      ],
    },
  },
  
  // 最後にeslint-config-prettierを追加して競合を解消
  eslintConfigPrettier,
);

競合チェックの実行

設定に競合がないか確認するには、CLIツールを使用します。

1
npx eslint-config-prettier src/App.tsx

競合がなければ何も出力されません。競合がある場合は、該当するルール名が表示されます。

React向け推奨ESLintルール

Reactプロジェクトで特に有効なESLintルールを紹介します。

React Hooksルール

React公式が提供するHooksルールは必須です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// eslint-plugin-react-hooksのルール
{
  rules: {
    // Hooksの呼び出しルール(必須)
    "react-hooks/rules-of-hooks": "error",
    
    // 依存配列の検証
    "react-hooks/exhaustive-deps": "warn",
  }
}

アクセシビリティルール

eslint-plugin-jsx-a11yを追加することで、アクセシビリティの問題を検出できます。

1
npm install -D eslint-plugin-jsx-a11y
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// eslint.config.jsに追加
import jsxA11y from "eslint-plugin-jsx-a11y";

// 設定内に追加
{
  plugins: {
    "jsx-a11y": jsxA11y,
  },
  rules: {
    ...jsxA11y.configs.recommended.rules,
    "jsx-a11y/alt-text": "error",
    "jsx-a11y/anchor-is-valid": "warn",
  },
}

Import順序ルール

eslint-plugin-importでインポート文の順序を統一できます。

1
npm install -D eslint-plugin-import
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 設定例
{
  rules: {
    "import/order": [
      "error",
      {
        groups: [
          "builtin",
          "external",
          "internal",
          "parent",
          "sibling",
          "index",
        ],
        "newlines-between": "always",
        alphabetize: { order: "asc", caseInsensitive: true },
      },
    ],
  },
}

Git Hooksでの自動実行

コミット前にLinter・Formatterを自動実行することで、品質を担保します。

huskyとlint-stagedのインストール

1
2
npm install -D husky lint-staged
npx husky init

pre-commitフックの設定

.husky/pre-commitファイルを編集します。

1
npx lint-staged

lint-stagedの設定

package.jsonに設定を追加します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ]
  }
}

この設定により、ステージングされたファイルのみに対してESLintとPrettierが実行されます。

CI/CDでの活用

GitHub ActionsでLinter・Formatterチェックを自動化する例を紹介します。

GitHub Actionsワークフロー

.github/workflows/lint.ymlを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
name: Lint and Format Check

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

jobs:
  lint:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        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

このワークフローにより、プルリクエスト作成時やプッシュ時にLinter・Formatterのチェックが自動実行されます。

VS Codeの設定

VS Codeで最適な開発体験を得るための設定を紹介します。

推奨拡張機能

  • ESLint(dbaeumer.vscode-eslint)
  • Prettier - Code formatter(esbenp.prettier-vscode)

ワークスペース設定

.vscode/settings.jsonを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ]
}

この設定により、ファイル保存時にPrettierによるフォーマットとESLintの自動修正が実行されます。

推奨拡張機能ファイル

.vscode/extensions.jsonを作成してチームで共有します。

1
2
3
4
5
6
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode"
  ]
}

トラブルシューティング

ESLintとPrettierの競合エラー

症状:ESLintとPrettierが異なるフォーマットを要求し、修正が無限ループになる

解決策

  1. eslint-config-prettierが正しくインストールされているか確認
  2. eslint.config.jseslintConfigPrettier最後に配置されているか確認
  3. 競合チェックを実行
1
npx eslint-config-prettier src/App.tsx

Flat Config形式への移行エラー

症状.eslintrc.*eslint.config.jsが混在してエラーが発生

解決策

  1. 古い.eslintrc.*ファイルを削除
  2. .eslintignoreを削除(Flat Configではignoresプロパティを使用)
  3. ESLintキャッシュをクリア
1
rm -rf node_modules/.cache/eslint

TypeScriptパーサーエラー

症状Parsing error: Cannot read file 'tsconfig.json'

解決策

parserOptions.projectのパスを確認します。

1
2
3
4
5
6
7
8
{
  languageOptions: {
    parserOptions: {
      project: ["./tsconfig.json"],
      tsconfigRootDir: import.meta.dirname,
    },
  },
}

VS CodeでESLintが動作しない

症状:VS Codeでエラーがハイライトされない

解決策

  1. ESLint拡張機能がインストールされているか確認
  2. VS Codeを再起動
  3. 出力パネルで「ESLint」を選択してエラーログを確認
  4. 以下のコマンドでESLintサーバーを再起動
1
Ctrl+Shift+P → ESLint: Restart ESLint Server

Prettierがファイルを無視する

症状:特定のファイルがフォーマットされない

解決策

  1. .prettierignoreに該当ファイルが含まれていないか確認
  2. .gitignoreに含まれていないか確認(Prettierは.gitignoreも参照)
  3. ファイル拡張子がサポートされているか確認

導入時の注意点

既存プロジェクトへの導入

大規模な既存プロジェクトに導入する際は、段階的なアプローチを推奨します。

  1. まずPrettierのみ導入:フォーマットを統一してから品質ルールを追加
  2. ルールを緩めに設定:最初はwarnレベルで開始し、徐々にerrorに変更
  3. ベースラインを設定:既存のエラーを一時的に無視する設定を検討
1
2
3
4
5
6
7
8
// 段階的導入の例
{
  rules: {
    // 最初はwarnで様子を見る
    "@typescript-eslint/no-explicit-any": "warn",
    "no-console": "warn",
  },
}

チームでの運用

  • 設定ファイルをリポジトリにコミット.prettierrceslint.config.js.vscode/settings.jsonを共有
  • 推奨拡張機能を明文化.vscode/extensions.jsonでチーム全員が同じ環境を構築
  • CIで強制チェック:ローカルで実行し忘れてもCIで検出

パフォーマンスの考慮

大規模プロジェクトでは、Linter・Formatterの実行時間が問題になることがあります。

  • lint-stagedの活用:変更されたファイルのみをチェック
  • キャッシュの活用:ESLintの--cacheオプションを使用
  • 不要なルールの無効化:使用していないプラグインのルールは読み込まない
1
2
3
4
5
6
{
  "scripts": {
    "lint": "eslint . --cache",
    "lint:fix": "eslint . --fix --cache"
  }
}

まとめ

本記事では、ReactプロジェクトにおけるESLint(Linter)とPrettier(Formatter)の導入方法を解説しました。

重要なポイントを振り返ります。

  • ESLintはコード品質Prettierはコードスタイルを担当する補完関係
  • Flat Config形式eslint.config.js)がESLint v9以降の標準
  • eslint-config-prettierでESLintとPrettierの競合を解消
  • Git HooksCI/CDで自動チェックを実施し、品質を担保
  • VS Code設定でファイル保存時に自動フォーマット・自動修正

これらの設定を適切に行うことで、チーム全体で一貫したコード品質を維持し、コードレビューの効率化やバグの早期発見につながります。

参考リンク