Next.js 15 対応とあわせて、ESLint と Prettier を Flat Config に移行した
はじめに
Next.js v15 では、ESLint v9 と Flat Config がデフォルトになり、Flat Config への以降が推奨されています。
従来の .eslintrc.*
, .eslintignore
ファイルで設定する方式は、ESLint v9 以降では deprecated になり、「ESLint v10 以降では完全に削除する」とアナウンスされています。
Flat config rollout plans - ESLint - Pluggable JavaScript Linter
A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease.
2025/3 現在では、Flat Config に関する情報はまだ少なく、Flat Config 未対応のプラグインなども存在します。
この記事では、Next.js の v14 -> v15 移行とあわせて、ESLint と Prettier の設定を Flat Config に移行した手順を紹介します。
Flat Config について
Flat Config は、ESLint v9 以降で導入された新しい設定方法です。
従来の .eslintrc.json
(eslintrc.js
) で設定するのではなく、eslint.config.js
(eslint.config.cjs
, eslint.config.mjs
) に設定をまとめます。
Flat Config では、設定内容を JavaScript のモジュールとして import して明示します。このため、プラグインとの依存関係をわかりやすく整理できるようになりました。
また、ignore 対象もあわせて設定できるようになりました。.eslintignore
が不要になり、設定をまとめて管理できることも、メリットになります。
さらに、公式による最適化で、パフォーマンスも向上しているようです。
Configuration Files - ESLint - Pluggable JavaScript Linter
A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease.
ESLint Flat Config 移行手順
レガシーパッケージの整理
まず、Flat Config に不要なパッケージを削除します。
pnpm remove @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-next
@typescript-eslint/parser
, @typescript-eslint/eslint-plugin
は、typescript-eslint に統合されているため、削除します。
typescript-eslint | typescript-eslint
Tooling which enables you to use TypeScript with ESLint
eslint-config-next は、現時点では Flat Config に未対応です。以下を参考に、該当するプラグインを個別に導入することで対応します。
How to use new "flat config" approach in Eslint? · vercel/next.js · Discussion #49337
Summary I have Eslint working in a TypeScript Next.js project, but I want to switch to the new "flat config" approach that Eslint offers. (Why is that not Next.js's default?) I created /eslint.conf...
必要なパッケージを追加
次に、Flat Config に対応したパッケージをインストールします。
pnpm add -D eslint prettier eslint-config-prettier eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-unused-imports eslint-plugin-tailwindcss @next/eslint-plugin-next typescript-eslint eslint-plugin-storybook
@next/eslint-plugin-next
は、Flat Config に対応したNext.js 公式のプラグインです。
typescript-eslint
は、ひとつ前の手順で削除した @typescript-eslint/parser
と @typescript-eslint/eslint-plugin
の統合パッケージです。
eslint-plugin-storybook
は、storybook 用のプラグインです。Storybook 用のルールを含めない場合は、導入しなくても大丈夫です。
ESLint のルール設定
対象ファイルと ignore 設定
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
ignores: [
'**/build/', '**/bin/', '**/dist/', '**/obj/', '**/out/',
'**/.next/', '**/node_modules/',
],
}
React + Next.js の基本ルール設定
React と Next.js の推奨ルールを適用します。
@next/eslint-plugin-next
は、Flat Config に対応した Next.js 公式のプラグインです。
eslintPluginReact.configs.flat.recommended,
eslintPluginReact.configs.flat['jsx-runtime'],
{
plugins: {
'react-hooks': eslintPluginReactHooks,
'@next': eslintPluginNext,
},
rules: {
...eslintPluginReactHooks.configs.recommended.rules,
...eslintPluginNext.configs.recommended.rules,
...eslintPluginNext.configs['core-web-vitals'].rules,
'@next/next/no-img-element': 'error',
'react/prop-types': 'off',
},
};
TypeScript 向けのルール設定
TypeScript の推奨ルールと、型情報を含めたチェックを有効にします。
tsEslint.configs.recommended,
{
languageOptions: {
parser: tsEslint.parser,
parserOptions: { project: './tsconfig.json' },
},
rules: {
'@typescript-eslint/no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_' },
],
'@typescript-eslint/explicit-function-return-type': 'off',
},
};
Tailwind CSS
Tailwind CSS を利用している場合、ルールセットを追加します。
tailwindcss,
import order と unused-imports の設定
import
の順序と、未使用の import
を自動で削除するルールを設定します。
{
plugins: { import: eslintPluginImport, 'unused-imports': eslintPluginUnusedImports },
rules: {
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index'], 'type'],
pathGroups: [
{ pattern: 'react', group: 'builtin', position: 'before' },
{ pattern: 'next/**', group: 'builtin', position: 'before' },
{ pattern: '@/components/**', group: 'internal', position: 'before' },
{ pattern: '@/lib/**', group: 'internal', position: 'before' },
],
alphabetize: { order: 'asc', caseInsensitive: true },
'newlines-between': 'never',
},
],
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'unused-imports/no-unused-imports': 'error',
},
}
Storybook 向けのルール設定
Storybook を利用するプロジェクト向けに、該当するルールを設定します。基本的なのは、このあたりでしょうか。
{
files: ['**/*.stories.@(ts|tsx)'],
plugins: {
storybook: eslintPluginStorybook,
},
rules: {
'storybook/await-interactions': 'error',
'storybook/context-in-play-function': 'error',
'storybook/default-exports': 'error',
'storybook/hierarchy-separator': 'error',
'storybook/meta-inline-properties': 'error',
'storybook/no-title-property-in-meta': 'error',
'storybook/prefer-pascal-case': 'error',
'storybook/story-exports': 'error',
'storybook/use-storybook-expect': 'error',
},
},
Prettier 設定
最後に、Prettier の設定を追加します。
eslintConfigPrettier,
ルールが競合するのを防ぐため、Prettier のルールを最後に記載しています。
Prettier Flat Config 移行手順
ESLint とあわせて、Prettier も prettier.config.mjs に移行します。
// @ts-check
export default {
printWidth: 80,
tabWidth: 2,
semi: true,
singleQuote: true,
trailingComma: 'es5',
bracketSpacing: true,
plugins: ['prettier-plugin-tailwindcss'],
};
prettier-plugin-tailwindcss
により、Tailwind CSS クラス順序を自動で整理しています。
個人的に、横に長くなりがちな Tailwind CSS においては、cn()
ユーティリティ (twMerge + clsx ) とあわせて、必須の設定だと思っています。
VSCode でファイル保存時に自動フォーマットする設定
ローカルの個人設定 or プロジェクト設定の .vscode/settings.json
に、以下を追加して、ファイル保存時に自動で ESLint + Prettier が動くように設定します。
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"editor.formatOnSave": true,
"eslint.useFlatConfig": true,
"eslint.enable": true
}
ESLint & Prettier の動作確認
ESLint のチェック
pnpm eslint . --fix
Prettier のフォーマット
pnpm prettier --write .
まとめ
Flat Config 移行により、設定ファイルがひとつにまとまって、見通しが良くなったと感じました。
以前よりもシンプルに設定を書けるようになり、個別のルール適用もわかりやすくなったため、今後のメンテナンスも楽になると思います。
最終的に完成した eslint.config.mjs
は、このブログの GitHub リポジトリで公開しているので、コピペして使っていただいても大丈夫です。
cakegaly-web/eslint.config.mjs at main · cakegaly/cakegaly-web
cakegaly's personal blog. Contribute to cakegaly/cakegaly-web development by creating an account on GitHub.
最近話題の Biome も気になっているので、今度試して比較してみる予定です。