はじめに
Next.js App Routerプロジェクトでは、ESLintとPrettierを適切に設定することで、コード品質の維持とチーム間のスタイル統一を実現できます。本記事では、ESLint Flat Config形式での最新の設定方法を解説します。
ESLintとPrettierの役割
| ツール | 役割 | 例 |
|---|
| ESLint | コード品質・問題検出 | 未使用変数、型エラー、セキュリティ問題 |
| Prettier | コードフォーマット | インデント、クォート、行の長さ |
パッケージのインストール
# ESLint関連
npm install -D eslint @eslint/js typescript-eslint eslint-plugin-react eslint-plugin-react-hooks
# Prettier関連
npm install -D prettier eslint-config-prettier
# Next.js ESLint
npm install -D @next/eslint-plugin-next
# インポート順序
npm install -D eslint-plugin-import eslint-plugin-simple-import-sort
# Husky & lint-staged
npm install -D husky lint-staged
ESLint Flat Config設定
eslint.config.mjs
// eslint.config.mjs
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import nextPlugin from '@next/eslint-plugin-next';
import importPlugin from 'eslint-plugin-import';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import prettier from 'eslint-config-prettier';
export default tseslint.config(
// グローバル無視パターン
{
ignores: [
'.next/**',
'node_modules/**',
'out/**',
'public/**',
'*.config.js',
'*.config.mjs',
],
},
// 基本設定
js.configs.recommended,
...tseslint.configs.recommended,
// React設定
{
files: ['**/*.{ts,tsx}'],
plugins: {
react,
'react-hooks': reactHooks,
},
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
settings: {
react: {
version: 'detect',
},
},
rules: {
...react.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'react/no-unescaped-entities': 'off',
},
},
// Next.js設定
{
files: ['**/*.{ts,tsx}'],
plugins: {
'@next/next': nextPlugin,
},
rules: {
...nextPlugin.configs.recommended.rules,
...nextPlugin.configs['core-web-vitals'].rules,
},
},
// インポート順序
{
files: ['**/*.{ts,tsx}'],
plugins: {
import: importPlugin,
'simple-import-sort': simpleImportSort,
},
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
// Node.js builtins
['^node:'],
// React/Next.js
['^react', '^next'],
// External packages
['^@?\\w'],
// Internal aliases
['^@/'],
// Parent imports
['^\\.\\.'],
// Same folder imports
['^\\.'],
// Style imports
['^.+\\.s?css$'],
],
},
],
'simple-import-sort/exports': 'error',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
},
},
// TypeScript追加ルール
{
files: ['**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
fixStyle: 'inline-type-imports',
},
],
'@typescript-eslint/no-import-type-side-effects': 'error',
},
},
// テストファイル
{
files: ['**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
},
// Prettierとの競合回避(最後に配置)
prettier
);
Prettier設定
.prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"useTabs": false,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"],
"tailwindConfig": "./tailwind.config.ts"
}
.prettierignore
.next
node_modules
out
public
pnpm-lock.yaml
package-lock.json
*.md
VSCode設定
.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.useFlatConfig": true,
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
.vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss"
]
}
Husky & lint-staged設定
Huskyのセットアップ
npx husky init
.husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
package.jsonにlint-staged設定
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"typecheck": "tsc --noEmit"
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{js,jsx,mjs}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,scss,md}": [
"prettier --write"
]
}
}
GitHub Actions CI
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run ESLint
run: pnpm lint
- name: Check formatting
run: pnpm format:check
- name: TypeScript type check
run: pnpm typecheck
- name: Build
run: pnpm build
カスタムESLintルール追加例
コンポーネント命名規則
// eslint.config.mjs に追加
{
files: ['**/components/**/*.tsx'],
rules: {
// コンポーネントファイルはPascalCaseで命名
'react/jsx-pascal-case': 'error',
},
},
Server Components用ルール
// eslint.config.mjs に追加
{
files: ['**/app/**/*.tsx'],
rules: {
// Server ComponentsでuseStateなどの使用を警告
'react-hooks/rules-of-hooks': 'off',
},
},
{
files: ['**/components/**/*.tsx'],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
},
},
トラブルシューティング
ESLintとPrettierの競合
// eslint.config.mjs の最後に prettier を配置
import prettier from 'eslint-config-prettier';
export default tseslint.config(
// ... 他の設定
prettier // 必ず最後に配置
);
型インポートの自動修正
// tsconfig.json
{
"compilerOptions": {
"verbatimModuleSyntax": true
}
}
パフォーマンス最適化
// eslint.config.mjs
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
まとめ
| 設定項目 | ファイル |
|---|
| ESLint | eslint.config.mjs |
| Prettier | .prettierrc |
| VSCode | .vscode/settings.json |
| Git Hooks | .husky/pre-commit |
| CI | .github/workflows/ci.yml |
参考文献