TypeScript + Next.js で最強の Lint 設定を考えたので誰よりも丁寧に説明する (husky もあるよ)

# はじめに

どうも、 yoshii です

最近、 Next.js でものを作ることが多く、 Next.js の Lint 設定のテンプレートを作ろうと思いました。
ここで、俺の考えた最強の Lint 設定を皆さんに共有し、誰よりもわかりやすく説明したいと思います。

また、より良い設定などがあれば遠慮なくコメント書いてください。
みんなの手でさらに最強の設定にしましょう。

# GitHub

以下のリポジトリに今回の設定を使用したサンプルプロジェクトを共有しています。
`.vscode/extensions.json` に必要な拡張機能を記載しているので、プロジェクトをローカルにクローンしてVScodeで開くと拡張機能の追加を促すポップアップが出ると思います。
今回の記事では、こちらのプロジェクトの設定の解説を行います。

https://github.com/yoshiishunichi/next-lint-template

また、 Tailwind CSS に対応したテンプレートプロジェクトもこちらに用意しました。
今回解説はしませんが、Tailwind CSS を使う人がいたらこちらの設定も確認してみてください。

https://github.com/yoshiishunichi/next-lint-template-tailwind

# 環境・構成

## 環境

- OS: mac
- node: v16.16.0
- パッケージマネージャ: yarn 1.22.19
- エディタ: Visual Studio Code

VScodeに、`ESLint` と `Prettier` と　`Stylelint` の拡張機能を入れておいてください。

### ESLint

https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint

### Prettier

https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

### Stylelint

https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint

## 構成

各ツールとその役割を箇条書きで簡単に説明します。

- ESLint
    - リンターです。コードの品質に関するエラーを出します。一応フォーマッターとしての機能もありますが、そちらは `Prettier`に任せます。
    - 対象ファイルは、 以下の拡張子とします。
        - js
        - jsx
        - ts
        - tsx
- Prettier
    - フォーマッターです。コードの内容には関係ないコードのルールを統一します。
    - 対象ファイルは、以下の拡張子とします。
        - js
        - jsx
        - ts
        - tsx
        - json
        - css
        - scss
- Stylelint
    - CSS のリンターです。
    - 対象ファイルは、以下の拡張子とします。
        - css
        - scss

# 設定

それでは設定を行なっていきます。

## Next.js プロジェクトの初期化

以下のコマンドでプロジェクトを初期化します。`next-lint-template`は好きな名前にしてください。
TypeScript じゃない人は`--ts`オプションなしで。

```
yarn create next-app next-lint-template --ts
```

## 必要なライブラリのインストール

以下のコマンドで必要なライブラリを一気にインストールできます。
筆者は SCSS を使うので、 `sass` と `stylelint-config-recommended-scss` を入れてます。
普通に CSS 派の人は入れなくて大丈夫ですが、対応する CSS 用のライブラリを入れる様にしてください。

```
yarn add -D eslint-config-prettier eslint-plugin-sort-keys-fix eslint-plugin-typescript-sort-keys eslint-plugin-unused-imports prettier stylelint stylelint-config-recess-order stylelint-config-standard sass stylelint-config-recommended-scss stylelint-config-prettier
```

## 各種設定ファイル

以下の3つのファイルを追加します。一番簡単だと思う `.json` 形式で設定しますが、`.js` だったり `.yml` だったりは好みで大丈夫です。

- .eslintrc.json
- .prettierrc.json
- .stylelintrc.json

### .eslintrc.json

ESLint の設定ファイルです。

```json:.eslintrc.json
{
  "extends": ["next/core-web-vitals", "prettier"],
  "plugins": ["import", "sort-keys-fix", "typescript-sort-keys", "unused-imports"],
  "rules": {
    "import/order": [
      "error",
      {
        "groups": [
          "builtin",
          "external",
          "internal",
          "parent",
          "sibling",
          "index",
          "object",
          "type"
        ],
        "newlines-between": "always",
        "alphabetize": {
          "order": "asc"
        }
      }
    ],
    "import/no-duplicates": "error",
    "@next/next/no-img-element": "off",
    "react/jsx-sort-props": "error",
    "sort-keys-fix/sort-keys-fix": "error",
    "typescript-sort-keys/interface": "error",
    "unused-imports/no-unused-imports": "error"
  }
}
```

何をやっているか軽く説明します。

- extends
    - 賢い人が作ってくれたルールを追加してます
        - ルールの中身は `eslint-config-*` の形で npm パッケージとして公開されているので GitHub から確認できます。
            - `prettier` と書かれているルールは `eslint-config-prettier` を追加していることになる
- plugins
    - ルールセットを追加しています
        - ここに追加するだけではルールが適用されず、下の "rules" でカスタマイズすることで使えます。
- rules
    - ルールをカスタマイズしています。
        - `unused-imports/no-unused-imports`
            - 使われてない import を削除
        - `import/order`
            - import の順番を定義した通りに整列
        - `import/no-duplicates`
            - 同じ ライブラリ から import されている module を 1 行にまとめる
        - `@next/next/no-img-element`
            - `next/image` ではなく通常の `img` タグを使うとエラーを吐く。
            - デフォルトで "warning" が設定されているが、筆者はたまに`img` タグを使うので "off" にしている
        - `react/jsx-sort-props`
            - JSX の props の順番を整列
        - `sort-keys-fix/sort-keys-fix`
            - Object のキーの順番を整列
        - `typescript-sort-keys/interface`
            - TypeScript の型定義のプロパティのキーの順番を整列


### .prettierrc.json

Prettier の設定ファイルです

```json:.prettierrc.json
{
  "trailingComma": "all",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": false,
  "jsxSingleQuote": false,
  "printWidth": 100
}
```

これは大体何やってるかわかると思います。
Prettier では、コードの内容に関与しないような、一般的なコードのルールを統一しています。

### .stylelintrc.json

Stylelint の設定ファイルです

```json:.stylelintrc.json
{
  "extends": [
    "stylelint-config-recess-order",
    "stylelint-config-recommended-scss",
    "stylelint-config-standard",
    "stylelint-config-prettier"
  ],
  "rules": {
    "selector-class-pattern": "^[a-z][a-zA-Z0-9-]+$"
  }
}
```

これも `.eslintrc.json` と似た感じです。

- extends 
    - 賢い人が作ったルールを適用してます
- rules 
    - `selector-class-pattern`
        - セレクターの名前を正規表現で指定します。
        - `stylelint-config-standard` がケバブケースしか許容していないのですが、 module CSS のことを考えてキャメルケースも許容しています。

## package.json を編集

`package.json` の `scripts` の項目に以下のコマンドを追加します。

```json:package.json
"lint": "next lint --ignore-path .gitignore",
"lint:fix": "next lint --ignore-path .gitignore --fix",
"lint:style": "stylelint --ignore-path .gitignore './**/*.{css,scss}'",
"lint:style:fix": "stylelint --ignore-path .gitignore --fix './**/*.{css,scss}'",
"format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css,scss}'",
```

これで、以下のようにコマンドを実行するとリンターやフォーマッターが走ってコードを自動修正してくれます。

```
yarn lint:fix
```
```
yarn lint:style:fix
```
```
yarn format
```

## .vscode/settings.json の追加

`.vscode/settings.json` を追加します。

```json:.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "stylelint.stylelintPath": "node_modules/stylelint",
  "stylelint.validate": ["css", "scss"],
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true
  },
  "css.validate": false,
  "scss.validate": false
}
```

デフォルトのフォーマッターを Prettier に設定し、 StyleLint と ESLint の動作についても設定しています。

これで、保存時に自動で整形が行われるようになりました！
とりあえず一旦ゴールです。
お疲れ様でした。

# huskyの導入

ちょっとしたおまけですが、`husky` の導入方法も説明しておきます。
`husky` というのは、各 Git 操作で特定のイベントが起きた時に設定したスクリプトを実行するようなツールです。
これに `lint-staged` というのを組み合わせると、コミット時に毎回リントチェックを走らせて、エラーが起きる場合コミットできないように設定したりできます。
コミットのたびに少し時間が取られますが、さらにコードの品質が保たれるためチームで開発するときにおすすめです。

## 必要なライブラリのインストール

以下のコマンドで新たに必要なライブラリをインストールしてください。

```
yarn add -D husky lint-staged
```

## 設定

以下のコマンドで `husky` を初期化します。

```
npx husky-init -y && yarn
```

`.husky/pre-commit` というファイルが作られるので、以下のように変更します。
コミットが完了する直前にこのコマンドが走ります。

```sh:.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged
```

## package.json を変更

以下の項目を追加します。

```json:package.json
  "lint-staged": {
    "*.{css,scss}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.json": [
      "prettier --write"
    ]
  }
```

これで、コミット時にコミット対象のファイルに対して毎回リントチェックが走るはずです。

お疲れ様でした！
`husky`の導入についても GitHub に追加していますので、良ければ参考にしてください。


# まとめ

Next.js の Lint 設定の説明でした。
最後まで読んでいただいてありがとうございます。
質問や感想、もっと良い設定等あればコメントで教えてくださると嬉しいです。

あと、普段はお酒を飲みながら悪趣味なアプリを作っています。
友達が少ないので、よかったら Twitter で友達になってください。

https://twitter.com/ganja_tuber

# 追記

## 2022-05-24

GitHub に公開しているテンプレートプロジェクトの方を少し変更しました。
CSS ファイルを SCSS ファイルに変えただけですが、一応共有です。

あと、TailwindCSS のテンプレートで、 `.stylelintrc.json` の rules にディレクティブでエラーが出ないように修正しています。

## 2022-07-09

ライブラリのアップデートを行いました。

## 2022-07-29

ライブラリのアップデートを行いました。

node のバージョンを変更し、リポジトリに `.node-version` ファイルを追加しました。

## 2022-08-03

TailwindCSS の 方のリポジトリで Prettier と StyleLint の競合を解消しました。
これにより `@apply` ディレクティブでクラス名のソートが有効になります。

## 2022-09-06

Prettier と StyleLint の競合を解消し、本文もそれに合わせて修正しました。
また、 GitHub の方で package.json 内の各種ライブラリのバージョンも上げています。

## 2022-10-18

.node-version 削除しました。
`next.conifg.js` をテンプレートに合わました。