ESLint のアップグレード及び調整作業を GitHub Copilot に全部してもらった話

## はじめに
ある React / TypeScript / vite の個人開発を**一挙にアップグレード**しようと思いました。

きっかけは`npm outdated`でほとんど更新が必要だったことと、一挙にアップグレードして対応する実験（経験蓄積）をしたかったためです。

個人開発だと誰の気兼ねなく自由に振る舞えるのでこういうときに便利です。

::: note warn
（当然ですが）本来一挙にアップデートないし、アップグレードなんてやるべきではないので注意してください。
:::

### 一挙にアップグレードする手順
※くどいですが推奨されません。今回はあくまで個人開発での実験的作業です。

```bash
# npm-check-updates をグローバルインストール
npm install -g npm-check-updates

# 変更対象を確認
ncu

# package.json を更新
ncu -u

# 一挙にアップグレード
npm install
```

### 個別アップデート・アップグレードの手順
```bash
# 更新対象をチェック
npm outdated

# 個別にアップデート・アップグレード
#（※事前にドキュメントなどで更新による影響をチェックしておく）
#（※ライブラリによっては codemod など良しなにアップデート・アップグレードしてくれる機能を提供している場合もある）
npm install 対象ライブラリ名@latest
```

## 面倒くさい`ESLint`v8からv9へのアップグレード及び移行
ご存知の方には釈迦に説法ですが、`ESLint`はv9から`FlatConfig`という破壊的変更が入っており、ただアップグレードするだけでなく、新たに`eslint.config.mjs(js)`を用意したり、そのファイルに適切な記述（設定）を行ったり、関連各種ライブラリのアップデートや新規インストールが必要になったりと、対応範囲が結構広いです。

> v8からv9へのESLintのバージョンアップって、単純にアップデートするだけでなく、関連する無数の外部ライブラリのアップデートも発生します。
> その外部ライブラリの中でも、v9に対応しているものとそうでないものがあったりするので、それに応じてライブラリのダウングレードを行う、もしくはアンインストールして代替ライブラリに変えるなどの対応も別途必要になります。
> 加えて今回は、Flat Config形式に移行しなければならないので、設定ファイルのコードの書き方も変更する必要があり、とてもコストを要する作業になることが予想できました。

https://zenn.dev/innovation/articles/83bc19a7db16e0

とはいえ、`ESLint`を外して静的解析（コードを実行せずに行なう検証）を無くすのは良くないのでアップグレードします。

<font color="gray">（前から`Biome`が気になっていたので試しても良かったのですが、それはまた今度の機会に取っておきます）</font>

アップグレードに際してふと、~~純粋にめんどくさかったこともあるのですが、~~ もしや **ドキュメント読み込みや情報収集・整理を通じた移行作業なんて、まさしくLLMやAIエージェントが得意とするところでは？** と思ったのです。

ただし、これまでAIを活用してきた経験上、すべてを丸投げすると中々思い通りにいかないケースも少なくなかったので、筆者の方で**各種ライブラリをアップデート（アップグレード）しておいて作業環境を整えて**おきました。

## Good to Know
`ESLint`v8 -> v9（`FlatConfig`）移行や設定を進める前に知っておくと良いことを紹介しておきます。

- 次の v10 では `FlatConfig` しかサポートしない予定
旧来の`eslintrc`形式は完全に廃止されるため早めの移行推奨
- 適応する`rule`が重複した場合（`files`プロパティでフィルタした後）配列の後ろのものが優先される
```js
export default [
  基本設定,      // 優先度: 低
  TypeScript設定,  // 優先度: 中  
  個別ファイル設定  // 優先度: 高 ← これが適用される
]
```

- `FlatConfig`は必ず1次元配列での単純な処理構造
- `override`（設定上書き）, `extends`（設定継承）の廃止
先述通りシンプルな配列ベースの上書き（後述優先ルール）仕様となる
```js
// 旧: eslintrc
{
  extends: [...],    // ❌ 廃止
  overrides: [...]   // ❌ 廃止
}

// 新: FlatConfig
export default [
  configA,  // 直接配置
  configB,  // 直接配置
  configC   // 直接配置
]
```
- JavaScript標準のモジュール解決: ESLint独自の文字列ベース解決から、標準的なES Modulesのimportへ
  - プラグイン指定
    - v8（旧`config`）まで
    `'@typescript-eslint'`
    - v9 （`FlatConfig`）
    `import typescript from '@typescript-eslint/eslint-plugin'`
  - 設定継承
    - v8（旧`config`）まで
    `'plugin:react/recommended'`
    - v9 （`FlatConfig`）
    `...react.configs.recommended.rules`
  - パーサー指定
    - v8（旧`config`）まで
    `'@typescript-eslint/parser'`
    - v9 （`FlatConfig`）
    `import parser from '@typescript-eslint/parser'`

## あとは頼んだ！ Github Copilot
記事タイトル通り今回、`Github Copilot`（エージェントモード - 確か `Claude 3.5 Sonnet`）に**ESlint v8 -> v9 アップグレードと調整作業の全てを対応**してもらいました。

作業において`Github Copilot`がいくつかエラーで詰まっていた箇所もあったので、他の人（チームメンバー）にも情報共有しやすいようマークダウンファイル（備忘録）も作成してもらいました。

## 処理結果
### ESLint 関連
- インポートされたライブラリ
```bash
npm install --save-dev
  @typescript-eslint/parser        # TypeScriptパーサー
  @typescript-eslint/eslint-plugin # TypeScript ESLintプラグイン
  eslint-plugin-react              # React用ESLintプラグイン
  eslint-plugin-react-hooks        # React Hooks用ルール
```

上記ライブラリをインストールして、以下の`eslint.config.mjs`をそのまま使えば、今回`Github Copilot`が調整してくれた静的解析を利用できます。

- `eslint.config.mjs`
```js
import typescript from "@typescript-eslint/eslint-plugin";
import typescriptParser from "@typescript-eslint/parser";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";

// 設定をエクスポート
export default [
    {
        // TypeScriptとTSXファイルに対する設定
        files: ["**/*.ts", "**/*.tsx"],
        // languageOptions： パーサーやその詳細なオプション設定、グローバル変数の定義、サポートするECMAScriptのバージョンなどを設定するプロパティ
        languageOptions: {
            parser: typescriptParser,       // TypeScriptパーサーの設定
            parserOptions: {
                ecmaVersion: "latest",      // 最新のECMAScript機能をサポート
                sourceType: "module",       // ESモジュール形式を使用
                ecmaFeatures: {
                    jsx: true               // JSX構文のサポートを有効化
                }
            }
        },
        // 使用するプラグインの設定
        plugins: {
            "@typescript-eslint": typescript,   // TypeScript用のESLintプラグイン
            react,                              // React用のESLintプラグイン
            "react-hooks": reactHooks           // React Hooks用のESLintプラグイン
        },
        // 各種ルールの設定
        rules: {
            /* Reactルール */
            "react/jsx-uses-react": "error",        // JSXコンポーネント内でのReactの適切な使用を確認
            "react/jsx-uses-vars": "error",         // JSX内での変数の使用状況を追跡
            "react-hooks/rules-of-hooks": "error",  // React Hooksのルールを厳格に適用（コンポーネントのトップレベルでのみ使用可能）
            "react-hooks/exhaustive-deps": "warn",  // useEffectの依存配列の検証（パフォーマンス最適化のため）
            /* TypeScriptルール */
            "@typescript-eslint/no-explicit-any": "warn",               // any型の使用を警告
            "@typescript-eslint/explicit-function-return-type": "off",  // 関数の戻り値型の明示を任意に設定
            "@typescript-eslint/no-unused-vars": "warn"                 // 未使用変数を警告
        }
    }
];
```

生成当初はコメントが入っていなかったのですが希望すると丁寧に入れてくれました。

加えて、今回のアップグレードで不要となった`.eslintrc.cjs`（v8系まで使われていたファイル）についても説明してくれて、削除までしてくれました。

強度としては必要最低限レベルで、環境や状況に応じて随時カスタマイズしていくベース設定の`eslint`という感じです。
この辺りのレビューは他の複数のAIに投げてレビューしてもらいました。
こういった点でもAIのお陰で作業効率や精度向上の恩恵を受けられている印象です。

さらには、未知への対応や言語習得などに関しても**コメント付きで頼むとキャッチアップ効率が高まる**ので、~~（楽をする目的以外でも）~~ そういった意味でもAIエージェントを活用するのは有益だと感じました。

---

ちなみに、蛇足ながら`vite`で初期セットアップ時（`npm create vite@latest`）に設定されている`eslint`は以下になります。

<details>
<summary>Viteで初期セットアップ時のESLint</summary>

- `eslint.config.js`
```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(
  // dist ディレクトリを ESLint のチェック対象から除外
  { ignores: ['dist'] },
  {
    // 基本設定の継承
    // - JavaScript の推奨設定
    // - TypeScript の推奨設定
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    // TypeScript ファイルを対象とする
    files: ['**/*.{ts,tsx}'],

    // 言語オプションの設定
    languageOptions: {
      // ECMAScript 2020 の機能を使用可能に
      ecmaVersion: 2020,
      // ブラウザのグローバル変数を使用可能に
      globals: globals.browser,
    },
    // React 関連のプラグインを設定
    plugins: {
      // React Hooksのルールを適用するプラグイン
      // - フックの依存配列チェック
      // - フックの呼び出し順序の検証
      'react-hooks': reactHooks,

      // React Fast Refreshのサポート用プラグイン
      // - 開発時のホットリロードを最適化
      // - コンポーネントの状態を保持したまま更新可能
      'react-refresh': reactRefresh,
    },

    // ルールの設定
    rules: {
      // React Hooks のルールを適用
      ...reactHooks.configs.recommended.rules,
      // Fast Refresh 関連のルール設定
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true }, // 定数のエクスポートを許可
      ],
    },
  },
)
```

- （インストールされる）関連ライブラリ
```bash
- @eslint/js@9.27.0
- eslint-plugin-react-hooks@5.2.0
- eslint-plugin-react-refresh@0.4.20
- eslint@9.27.0
- globals@16.1.0
- typescript-eslint@8.32.1
```

</details>

### 作業履歴ドキュメント
ドキュメントはマークダウンファイルで生成してもらいました。

::: note
今回そんな予定はなかったものの、ものによっては生成したドキュメントを別のAIエージェントに投げて他の作業をしてもらうというユースケースもあるようなので、基本的にドキュメントはマークダウン形式で出してもらうようにしています。
:::

今回の作業において`Github Copilot`が詰まったのは以下の部分になります。

1. **必要なパッケージの不足**
作業完了という報告を受けて`npm run lint`すると全く動かない（設定エラーが出力されていた）
2. **TypeScript/Reactのパース設定の不足**
上記対応をしてもらった上で再度`npm run lint`すると解析エラーが大量に出力される
3. **適切なルールセットの不足**
1の対応と合わせて2と3を同時に解消（アップグレード及び調整作業の完了）

<details><summary>ドキュメントの内容（長いのでこちらに）</summary>

以下は`Github Copilot`が生成した、ほぼ原文です（一部筆者で微調整）

## 発生していた問題と解決策

### 発生していた問題
1. 必要なパッケージの不足
2. TypeScript/Reactのパース設定の不足
3. 適切なルールセットの不足

### 解決策のポイント
1. 必要なパッケージを全てインストール
2. TypeScriptとReactの両方に対応する包括的な設定を実装
3. プロジェクトの特性に合わせた適切なルールセットを設定

## インストール済みパッケージ

```bash
npm install --save-dev
  @typescript-eslint/parser        # TypeScriptパーサー
  @typescript-eslint/eslint-plugin # TypeScript ESLintプラグイン
  eslint-plugin-react             # React用ESLintプラグイン
  eslint-plugin-react-hooks       # React Hooks用ルール
```

## 設定ファイル構造

`eslint.config.mjs` には以下の設定が含まれています：

### インポート設定
```javascript
import typescript from "@typescript-eslint/eslint-plugin";
import typescriptParser from "@typescript-eslint/parser";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
```

### パーサー設定
- TypeScriptパーサーを使用
- ECMAScript最新バージョンをサポート
- モジュール形式のソースコード
- JSXサポートを有効化

### プラグイン
- TypeScript (`@typescript-eslint`)
- React (`eslint-plugin-react`)
- React Hooks (`eslint-plugin-react-hooks`)

### 適用ルール

#### TypeScriptルール
- `@typescript-eslint/no-explicit-any`: any型の使用を警告
- `@typescript-eslint/explicit-function-return-type`: 関数戻り値型の明示は任意
- `@typescript-eslint/no-unused-vars`: 未使用変数を警告

#### Reactルール
- `react/jsx-uses-react`: React使用の検知
- `react/jsx-uses-vars`: JSX内の変数使用検知
- `react-hooks/rules-of-hooks`: Hooksルールの強制
- `react-hooks/exhaustive-deps`: 依存配列の検証（警告レベル）

## プロジェクトでの使用方法

### ESLintの実行
```bash
# 基本的な実行方法
npm run lint

# または直接 ESLint を実行
npx eslint . --ext .ts,.tsx
```

## トラブルシューティング

エラーが発生した場合の一般的な解決手順：

1. パッケージの再インストール
```bash
rm -rf node_modules
npm install
```

2. ESLintの設定キャッシュのクリア
```bash
npm run lint -- --cache --fix
```

3. TypeScriptの設定との整合性確認
- `tsconfig.json` の設定がESLintの設定と矛盾していないことを確認

## メンテナンス

定期的に以下を実施することを推奨します：

1. パッケージの更新確認
```bash
npm outdated
```

2. セキュリティ脆弱性のチェック
```bash
npm audit
```

3. 新しいルールやベストプラクティスの確認と適用

## 今後の推奨事項

1. 新しいTypeScriptやReact機能を使用する際は、ESLintの設定を適宜更新
2. プロジェクトの要件に応じてルールの調整が必要な場合は、`rules`セクションを更新
3. チーム開発の場合は、この設定をチームで共有し、一貫性のあるコーディング規約として活用

## プロジェクト固有の注意点

1. コンポーネントの構造
   - `src/components/` 以下の各機能ごとのディレクトリ構造に合わせたESLintルールを適用
   - hooks、utils、tsディレクトリの規約を遵守

2. 型チェック
   - `tsconfig.json`との整合性を維持
   - コンポーネント間のインターフェースの一貫性を確保

3. パフォーマンス最適化
   - React Hooksのルール（特に依存配列）を適切に管理
   - 不要なレンダリングを防ぐためのコード品質維持

---
最終更新日: 2025年5月21日

</details>

---

ドキュメントには、問題と解決策をはじめ、トラブルシューティングや今後のメンテナンス、推奨事項なども盛り込まれていました。

こちらで頼んではいないものの、AIが自律的に必要と判断した情報も記載されていて痒い所に手が届くものだと感心しました。

## さいごに
今回、`Github Copilot`にほぼほぼ全て対応してもらったのですが、作業環境の構築を行った上で依頼した方がやはり効率的なように感じます。

あと、これは個人差があるかもですが途中で書いた通り、AIエージェントを利用することでキャッチアップ効率も高まる印象です。

しかし、すべてを任せきりにせず人間側でも事前に情報収集しておき、AIの自律的な作業の軌道修正が適宜行えるようにしておくのも重要だと感じました。

ここまで読んでいただき、ありがとうございました。

## 参考

https://eslint.org/docs/latest/use/configure/migration-guide

https://zenn.dev/cybozu_frontend/articles/about-eslint-flat-config