turbo.jsonの基本的な設定とワークスペースでの活用方法

## はじめに
今回は、モノレポ（monorepo）開発で使用される`turbo.json`の基本的な設定と、複数パッケージ間の依存関係による実行順序について解説していきます。

## turbo.jsonとは？
`turbo.json`は、Turborepoというビルドシステムの設定ファイルです。複数のプロジェクトやパッケージを効率的に管理・ビルドするために使用されます。

## 基本的な設定例
まずは、典型的な`turbo.json`の例を見てみましょう。

```json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "typecheck": {
      "dependsOn": ["^typecheck"]
    },
    "dev": {
      "persistent": true,
      "cache": false
    }
  }
}
```

## 設定項目の解説

### 1. $schema
```json
"$schema": "https://turbo.build/schema.json"
```
これは、VSCodeなどのエディタがこの設定ファイルを正しく理解するためのスキーマ定義です。

### 2. buildタスク
```json
"build": {
  "dependsOn": ["^build"],
  "outputs": [".next/**", "!.next/cache/**"]
}
```

- `dependsOn`: `^build`は依存しているパッケージのビルドを先に実行する
- `outputs`: ビルド成果物の出力先を指定（`.next/**`以下のファイル、ただしキャッシュは除外）

### 3. typecheckタスク
```json
"typecheck": {
  "dependsOn": ["^typecheck"]
}
```
- `dependsOn`: 依存パッケージの型チェックを先に実行する

### 4. devタスク
```json
"dev": {
  "persistent": true,
  "cache": false
}
```
- `persistent`: 常時実行状態を維持
- `cache`: 開発中は常に最新のコードを反映させるためキャッシュを無効化

## 実践的なワークスペース構成

典型的なプロジェクト構成を見てみましょう。

```
my-monorepo/
  ├── packages/
  │   ├── ui-components/
  │   │   ├── package.json
  │   │   └── tsconfig.json
  │   └── shared-utils/
  │       ├── package.json
  │       └── tsconfig.json
  ├── apps/
  │   └── web/
  │       ├── package.json
  │       └── tsconfig.json
  └── turbo.json
```

### 各パッケージの設定と依存関係

**packages/shared-utils/package.json**
```json
{
  "name": "@my-monorepo/shared-utils",
  "scripts": {
    "typecheck": "tsc --noEmit",
    "build": "tsc"
  }
}
```

**packages/ui-components/package.json**
```json
{
  "name": "@my-monorepo/ui-components",
  "dependencies": {
    "@my-monorepo/shared-utils": "workspace:*"  // shared-utilsへの依存を定義
  },
  "scripts": {
    "typecheck": "tsc --noEmit",
    "build": "tsc"
  }
}
```

**apps/web/package.json**
```json
{
  "name": "@my-monorepo/web",
  "dependencies": {
    "@my-monorepo/ui-components": "workspace:*",  // ui-componentsへの依存を定義
    "@my-monorepo/shared-utils": "workspace:*"    // shared-utilsへの依存を定義
  },
  "scripts": {
    "typecheck": "tsc --noEmit",
    "dev": "next dev",
    "build": "next build"
  }
}
```

## パッケージ間の依存関係を理解する

package.jsonの`dependencies`で定義された依存関係から、以下のような依存グラフが形成されます：

```
web → ui-components → shared-utils
web → shared-utils
```

この依存関係は以下のように形成されています。
1. `web`は`ui-components`と`shared-utils`の両方に依存（web/package.jsonのdependenciesで定義）
2. `ui-components`は`shared-utils`に依存（ui-components/package.jsonのdependenciesで定義）
3. `shared-utils`は他のパッケージに依存していない

`workspace:*`は同じモノレポ内のパッケージを参照することを示しています。

## タスクの実行順序を理解する

`turbo typecheck`を実行した場合、

```json
{
  "tasks": {
    "typecheck": {
      "dependsOn": ["^typecheck"]
    }
  }
}
```

この`^typecheck`は「依存しているパッケージのtypecheckを先に実行する」という意味です。

### 実行順序

package.jsonで定義された依存関係に基づいて、以下の順序で実行されます。

1. **shared-utils**: 他に依存していないため、最初に実行可能
2. **ui-components**: `shared-utils`の型チェックが完了するのを待ってから実行
3. **web**: `shared-utils`と`ui-components`両方の型チェックが完了するのを待ってから実行

### なぜこの順序なのか？

- `shared-utils`は他のパッケージに依存していないため、最初に安全に実行できます
- `ui-components`は`shared-utils`を使用しているため、`shared-utils`の型が正しいことを確認してから型チェックを行う必要があります
- `web`は両方のパッケージを使用しているため、両方の型が正しいことを確認してから型チェックを行う必要があります

## キャッシュの活用

Turborepoは実行結果をキャッシュします。

- 変更のないパッケージは前回の結果を再利用
- パッケージごとにキャッシュを管理
- チーム間でリモートキャッシュの共有も可能

## まとめ

- `turbo.json`でタスクの依存関係と実行順序を制御
- `package.json`の`dependencies`でパッケージ間の依存関係を定義
- `workspace:*`で同じモノレポ内のパッケージを参照
- 依存関係グラフに基づいて適切な実行順序が決定される
- キャッシュ機能により、ビルド時間を大幅に短縮可能

## 参考リンク
- [Turborepo 公式ドキュメント](https://turbo.build/repo)
- [Monorepo Handbook](https://turbo.build/repo/docs/handbook)