はじめに#
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はコードフォーマッターであり、コードの見た目を統一します。
- インデントの統一
- クォートスタイルの統一(シングル/ダブル)
- セミコロンの有無
- 行の折り返し
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ファイルを編集します。
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が異なるフォーマットを要求し、修正が無限ループになる
解決策:
eslint-config-prettierが正しくインストールされているか確認
eslint.config.jsでeslintConfigPrettierが最後に配置されているか確認
- 競合チェックを実行
1
|
npx eslint-config-prettier src/App.tsx
|
Flat Config形式への移行エラー#
症状:.eslintrc.*とeslint.config.jsが混在してエラーが発生
解決策:
- 古い
.eslintrc.*ファイルを削除
.eslintignoreを削除(Flat Configではignoresプロパティを使用)
- 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でエラーがハイライトされない
解決策:
- ESLint拡張機能がインストールされているか確認
- VS Codeを再起動
- 出力パネルで「ESLint」を選択してエラーログを確認
- 以下のコマンドでESLintサーバーを再起動
1
|
Ctrl+Shift+P → ESLint: Restart ESLint Server
|
Prettierがファイルを無視する#
症状:特定のファイルがフォーマットされない
解決策:
.prettierignoreに該当ファイルが含まれていないか確認
.gitignoreに含まれていないか確認(Prettierは.gitignoreも参照)
- ファイル拡張子がサポートされているか確認
導入時の注意点#
既存プロジェクトへの導入#
大規模な既存プロジェクトに導入する際は、段階的なアプローチを推奨します。
- まずPrettierのみ導入:フォーマットを統一してから品質ルールを追加
- ルールを緩めに設定:最初は
warnレベルで開始し、徐々にerrorに変更
- ベースラインを設定:既存のエラーを一時的に無視する設定を検討
1
2
3
4
5
6
7
8
|
// 段階的導入の例
{
rules: {
// 最初はwarnで様子を見る
"@typescript-eslint/no-explicit-any": "warn",
"no-console": "warn",
},
}
|
チームでの運用#
- 設定ファイルをリポジトリにコミット:
.prettierrc、eslint.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 HooksとCI/CDで自動チェックを実施し、品質を担保
- VS Code設定でファイル保存時に自動フォーマット・自動修正
これらの設定を適切に行うことで、チーム全体で一貫したコード品質を維持し、コードレビューの効率化やバグの早期発見につながります。
参考リンク#