📑

ESlint入門(Next.js)

に公開

はじめに

今までもESlintを使用していましたがきちんと理解していませんでした。
ver9.0.0にて大きな変更があったこともあり勉強と忘備録のために本記事を作成しました。
とても分かりやすく記事をまとめてくださっている方がいたので、その内容をインプットするためにまとめた記事となっています。

https://zenn.dev/hayato94087/books/58a08432c7066e

ESlintとは

ESlintとはJavaSctiptやTypeScriptの静的解析ツールです。
設定ファイルに設けたルールに則り、違反している場合は警告やエラーを通知するでけでなく、自動修正することもできます。
これによりコードの品質を向上させ、コードの可読性を高め、保守しやすくすることができます。
さらにチーム内でコーディングスタイルを統一することができます。
Eslintはコード成形ツールのPrettierやテストフレームワークのJest・Vitest、Git操作、ビルドツールと連携することができるのも特色です。

バージョンについて

2024年3月にver.9.0.0がリリースされ、ルールの設定形式がフラット形式にデフォルト化されました。本記事ではフラット設定形式に対応しています。

プロジェクト作成

今回はcreate-next-appを使用します。

package.json
    {
      "name": "zenn-eslint",
      "version": "0.1.0",
      "private": true,
      "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start",
        "lint": "next lint"
      },
      "dependencies": {
        "react": "^19.0.0",
        "react-dom": "^19.0.0",
        "next": "15.3.2"
      },
      "devDependencies": {
        "typescript": "^5",
        "@types/node": "^20",
        "@types/react": "^19",
        "@types/react-dom": "^19",
        "@tailwindcss/postcss": "^4",
        "tailwindcss": "^4",
        "eslint": "^9",
        "eslint-config-next": "15.3.2",
        "@eslint/eslintrc": "^3"
      }
    }

フラット設定形式

プロジェクト内にはeslint.config.mjsというファイルが作成されています。
従来はeslintrcという設定ファイルを使用していましたがver.9より変更となっています。

現在の状態

eslint.config.mjsの状態を見てみます。

eslint.config.mjs
    import { dirname } from "path";
    import { fileURLToPath } from "url";
    import { FlatCompat } from "@eslint/eslintrc";
    
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    
    const compat = new FlatCompat({
      baseDirectory: __dirname,
    });
    
    const eslintConfig = [
      ...compat.extends("next/core-web-vitals", "next/typescript"),
    ];
    
    export default eslintConfig;

eslintConfigにはあらかじめNext.jsが推奨する2つのルールセットが適用されています。

  • next/core-web-vitals:Web パフォーマンス指標に関するルール
  • next/typescript:TypeScript のコード品質向上のためのルール

ESLintの動作確認

2つのルールを追加します。

  • @typescript-eslint/consistent-type-imports
     
    一貫性のあるインポートをサポートするためのルール
    自動修正をテストするために追加

  • no-console
     
    consoleの消し忘れがないか確認するためのルール
    警告も含めて厳格にチェックするために追加

eslint.config.mjs
  const eslintConfig = [
          ...compat.extends("next/core-web-vitals", "next/typescript"),
          {
            files: ["**/*.{js,mjs,cjs,ts,tsx}"],
            rules: {
              "@typescript-eslint/consistent-type-imports": [
                "error",
                { prefer: "type-imports" },
              ],
              "no-console": "warn",
            },
          },
        ];

動作確認のためpage.tsxを変更します。

page.tsx
    import { FC } from "react";
    
    const Page: FC = () => {
      console.log("hello world");
      return (
        <main>
          <div className="flex justify-center items-center h-screen">
            <div className="flex flex-col items-center">
              <h1 className="text-2xl font-bold">Hello World</h1>
            </div>
          </div>
        </main>
      );
    };
    
    export default Page;

typeを省略しているimport文にエラーが出ています。
consoleがあるため警告がでています。

問題を確認してみます。

npm run lint

自動修正してみます。

npm run -- --fix


エラーがでていたimport文に自動でtypeが追記され、エラーが解消されています。

クリーンアップします。

git reset --hard HEAD; git clean -fd

ESLint対象外ファイルを指定

npm run lintではなくnpx eslintを実行してみます。

npx eslint

するとターミナルに大量のエラーがはかれます。
これは、.nextディレクトリやnode_modulesディレクトリにあるファイルに対しても実行されているためです。
これらには適用されてほしくないので実行対象外のファイルを指定します。

eslint.config.mjs
const eslintConfig = [
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  {
    ignores: ["**/.next/**", "**/node_modules/**"],
  },
];

もう一度実行してみます。

npx eslint

先ほどでていたエラーが出なくなりました。

ESLintスクリプトのカスタマイズ

package.json
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
-   "lint": "next lint"
+   "lint": "next lint && npx eslint . --ext .js,.jsx,.ts,.tsx,.mjs",
+   "lint:fix": "next lint --fix && npx eslint . --ext .js,.jsx,.ts,.tsx,.mjs --fix"
  },
  • npm run lint - 通常のlintチェック
  • npm run lint:fix - 修正可能な問題を修正

Next.js固有のESLintの設定

next.config.tsのESLint設定について解説します。
現在の状態を見てみます。

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
};

export default nextConfig;

ignoreDuringBuilds

ビルド時のESLintの動作を制御します。
trueにするとビルド時にESLintのエラーがあってもビルドすることができます。
開発初期はfalse、開発が進んだ段階でfalseにすることで厳格なチェックを行えます。
デフォルトはtrueです。

dirs

特定のディレクトリのみをESLintの対象にすることができます。

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  eslint: {
    dirs: ["src/pages", "src/components"],
  },
};

export default nextConfig;

Prettierの導入

Prettierとパッケージをインストールします。

  • prettier : Prettier本体
  • prettier-plugin-tailwindcss : TailwindCSSをフォーマットするプラグイン
npm i -D prettier prettier-plugin-tailwindcss

Prettier設定ファイルを作成します。

prettier.config.mjs
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
const config = {
  plugins: ["prettier-plugin-tailwindcss"],
};

export default config;

スクリプトを追加します。

package.json
{
 "scripts": {
+    "format": "prettier --check \"**/*.{ts,tsx,js,jsx,cjs,mjs,md,json,lintstagedrc,yml,yaml}\" --cache",
+    "format:fix": "prettier --write \"**/*.{ts,tsx,js,jsx,cjs,mjs,md,json,lintstagedrc,yml,yaml}\" --cache",
 },
}

npm run format : コードフォーマットが必要なファイルの警告として列挙されます。

npm run format:fix : 自動でフォーマットされます。

GitHooksの導入

GitHooksを導入し、ステージングされたファイルに自動的にESLintを実行するための設定をします。
Huskyとlint-stagedを使用します。

GitHooksとは

Gitリポジトリで特定のイベントが発生した場合に自動で実行されるスクリプトです。

Huskyとは

Gitフックを用いてステージングされたファイルにテストを行うことができるツールです。

lint-stagedとは

Gitでステージングされたファイルに対してLinterを実行することができるツールです。

パッケージをインストールします。

npm i -D husky lint-staged
npx husky init

コマンドの実行順を制御できるようにするために.husky/pre-commitファイルを編集します。

pre-commit
- npm test
+ npx lint-staged --concurrent false --allow-empty

Huskyの設定ファイルを作成します。

.lintstagedrc
{
  "*.{js,jsx,ts,tsx,mjs}": ["eslint --fix"],
  "**/*.{ts,tsx,js,jsx,cjs,mjs,md,json,lintstagedrc,yml,yaml}": [
    "prettier --write"
  ]
}

正常に動作するか確認するためファイルを編集します。

page.tsx
import { FC } from "react";

const Page: FC = () => {
  return (
    <main>
      <div className="flex h-screen items-center justify-center">
        <div className="flex flex-col items-center">
          <h1 className="text-2xl font-bold">Hello World</h1>
        </div>
      </div>
    </main>
  );
};

export default Page;
eslint.config.mjs
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
  baseDirectory: __dirname,
});

const eslintConfig = [
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  {
    files: ["**/*.{js,mjs,cjs,ts,tsx}"],
    rules: {
      "@typescript-eslint/consistent-type-imports": [
        "error",
        { prefer: "type-imports" },
      ],
    },
  },
];

export default eslintConfig;

git addします。

git add .

ステージングされているpage.tsxを見てみると自動修正されていることがわかります。

commitしてpage.tsxを見てみます。

git commit -m "ESLint  の設定を追加"

GitHub Acrtionsの導入

GitHub Actionsの設定ファイルとカスタムアクションを作成します。

.github/workflows/ci.yml
name: CI

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

env:
  NODE_VERSION: "20.9.0"
  NPM_VERSION: "10.9.2"

jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Setup environment
        uses: ./.github/actions/setup
        with:
          node-version: ${{ env.NODE_VERSION }}
          npm-version: ${{ env.NPM_VERSION }}

  lint:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
        with:
          node-version: ${{ env.NODE_VERSION }}
          npm-version: ${{ env.NPM_VERSION }}
      - run: npm run lint

  format:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
        with:
          node-version: ${{ env.NODE_VERSION }}
          npm-version: ${{ env.NPM_VERSION }}
      - run: npm run format

  typecheck:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup
        with:
          node-version: ${{ env.NODE_VERSION }}
          npm-version: ${{ env.NPM_VERSION }}
      - run: npm run typecheck

.github/actions/setup/action.yml
name: "Setup and install"
description: "Common setup steps for Actions"

inputs:
  node-version:
    description: "Node.js version"
    required: true
  npm-version:
    description: "NPM version"
    required: true

runs:
  using: composite
  steps:
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: "npm"

    - name: Install dependencies
      shell: bash
      run: npm install --frozen-lockfile

コミット、マージします。

git add . && git commit -m "Next.js プロジェクトに GitHub Actions を導入" &&
git checkout main &&
git merge feature

githubのActions>Jobs>lintを見てみます。

npm run lintが実行されていることがわかります。

まとめ

ver.9からデフォルト化されたflat設定形式とGitフックとCI/CDにおけるESLintの設定方法について学びました。冒頭に挙げたZennの記事が大変わかりやすく、勉強になりました。次はCI/CDについて学びたいと思います。

Discussion