TurborepoのESLint及びPrettierをBiomeに移行した手順

## はじめに
- Turborepoに標準インストールされていたESLintとPrettierを辞め、Biomeに移行する必要が生じたので、移行に要した手順を公開する
- パッケージ構成は以下の通り
```
(root)
|----apps
|    |----web ← ワークスペース
|
|----packages
|    |----ui ← ワークスペース
|    |----eslint-config ← ワークスペース
```

## Turborepoの前提知識
### `turbo lint`を実行すると、なぜwebやuiのlintが実行されるのか？
- Turborepoのルートディレクトリに存在する`turbo.json`を見てみる
```turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
```
- 9～11行目に`turbo lint`が実行された際のPipelineの依存関係が記載されている
- `"dependsOn": ["^lint"]`という記載があり、下位のワークスペースの`lint`コマンドも実行されるようになっている
- web及びrepo/uiの`package.json`を確認してみる
```json
{
  "name": "web",
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component"
  },
}
```
```json
{
  "name": "@repo/ui",
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component"
  },
}
```

## 移行手順

### 作業の順序

- 依存関係が下位のワークスペースから実施していく
- 今回は以下の順で実施
  - apps/web
  - ui
  - (root)
  - eslint-config

### apps/web

#### ESLintの依存関係の除去作業

- package.jsonを見て、ESLintに関連するパッケージをアンインストールする
```
$ cd apps/web
$ pnpm remove @next/eslint-plugin-next
$ pnpm remove @repo/eslint-config
$ pnpm remove @types/eslint
$ pnpm remove eslint
$ pnpm remove eslint-config-next
$ pnpm remove eslint-plugin-storybook
```
- package.jsonのscriptsからlintを除去する
```json
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint . --max-warnings 0", ← この行を削除する
    "test": "vitest run",
    "coverage": "vitest run --coverage",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  }
```

- `.eslintrc.js`を削除する

#### Biomeのインストール作業

- Biomeのインストールとbiome.jsonの生成を行う
```
$ cd apps/web
$ pnpm add -D --save-exact @biomejs/biome
$ npx @biomejs/biome init
```

- package.jsonのscriptsにcheck、lint、formatを追加する
  - biome check/lint/formatの後ろには、インプットしたいディレクトリを半角スペース区切りで羅列する
```json
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "vitest run",
    "coverage": "vitest run --coverage",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "check": "biome check ./__test__ ./.storybook ./src  ./mocks", ← この行を追加する
    "lint": "biome lint --apply ./__test__ ./.storybook ./src ./mocks", ← この行を追加する
    "format": "biome format --write ./__test__ ./.storybook ./src ./mocks" ← この行を追加する
  }
```

- biome.jsonにlinterやfomatterにオリジナルの定義を加える
  - fomatter
    - デフォルトのインデントがタブなので、インデントは半角スペース4つに変更した
  - files
    - 無視したいファイルorディレクトリを定義した
```json
{
	"$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
	"organizeImports": {
		"enabled": true
	},
	"linter": {
		"enabled": true,
		"rules": {
			"recommended": true
		}
	},
	"formatter": {
		"indentStyle": "space",
		"indentWidth": 4
	},
	"files": {
		"ignore": [
			"./src/apiclient/**/*"
		]
	}
}
```

#### 動作確認
- 以下のスクリプトをそれぞれ実行し、有効かどうかを確認する
```
pnpm check
pnpm lint
pnpm format
```

### ui

#### ESLintの依存関係の除去作業
- apps/webで行ったことと同じことを実施する

#### Biomeのインストール作業
- apps/webで行ったことと同じことを実施する

#### 動作確認
- apps/webで行ったことと同じことを実施する

### (root)

#### ESLintの依存関係の除去作業

- package.jsonを見て、ESLintに関連するパッケージをアンインストールする
```
$ pnpm remove @repo/eslint-config
```

- package.jsonを見て、prettierに関連するパッケージをアンインストールする
```
$ pnpm remove prettier
```

- package.jsonのscriptsからprettierを除去する
```json
"scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "check": "turbo check",
    "lint": "turbo lint",
    "format": "prettier --write \"**/*.{ts,tsx,md}\"" ← この行を削除する
  }
```

#### Turborepo Pipelineの設定

- package.jsonのscriptsにcheck、formatを追加する
```json
"scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "check": "turbo check", ← この行を追加する
    "lint": "turbo lint",
    "format": "turbo format" ← この行を追加する
  }
```

- turbo.jsonを見て、pipelineにcheck、formatを加える
  - これにより、下位のワークスペースのscriptが実行されるようになる
```
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "check": {
      "dependsOn": ["^check"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "format": {
      "dependsOn": ["^format"]
    }
  }
}
```

#### 動作確認
- 以下のスクリプトをそれぞれ実行し、Pipelineの定義通り、Pipeline定義上依存関係のあるワークスペースのスクリプトが実行されるかを確認する
```
pnpm check
pnpm lint
pnpm format
```

### eslint-config

#### ワークスペースの除去
- eslint-config自体が不要になったので、ワークスペースごと削除する

### リファクタリング
- プロジェクト全体に対し「eslint」や「prettier」で検索を行い、リファクタリングを実施する

### あとがき
- Turborepoの移行はそれほど複雑でないことが分かったので、今後も採用していきたい