TurborepoでMonorepoプロジェクトを管理する

5 分

1. なぜMonorepoを選ぶのか?

Monorepo(単一コードリポジトリ)は、複数の独立したプロジェクトやパッケージを1つのコードリポジトリに保存する戦略です。各プロジェクトが個別のリポジトリを持つPolyrepo方式と比べて、Monorepoにはいくつかの大きな利点があります。

  • コード共有:異なるプロジェクト間でコンポーネント、ユーティリティ関数、型定義を非常に簡単に共有できます。
  • アトミックなコミット:1つの機能変更が複数のパッケージに関係する場合でも、1回のコミットで完了でき、バージョンの一貫性を保てます。
  • 依存関係管理の簡素化:すべてのプロジェクトが1つのnode_modulesを共有するか、pnpm/yarn workspaceで最適化するため、依存関係の競合やバージョンの不一致を減らせます。

しかしリポジトリが大きくなると、Monorepoにはビルド性能という課題も生じます。

2. Monorepoの悩み

リポジトリにdocswebapp、そして共有のuiコンポーネントライブラリがあると想像してください。docsの誤字を1つ直しただけなのに、webappuiを含むリポジトリ内の全プロジェクトが再ビルド、再テストされることは最も避けたいはずです。

Lernaなど従来のMonorepo管理ツールは、タスクのオーケストレーションやビルドキャッシュに不十分な点があり、次の問題につながります。

  • 作業の重複:コードの大部分が変わっていなくても、CI/CDを実行するたびにすべてを最初からビルドし、テストします。
  • 長いビルド時間:複数のCPUコアを活用してタスクを効率よく並列実行できません。
  • 複雑なスクリプト:タスクの実行順序を手動で制御するために、複雑なpackage.jsonスクリプトを書く必要があります。

3. Turborepo:速度のために生まれた

TurborepoはJavaScript/TypeScriptのMonorepo向けに設計された高性能ビルドシステムで、後にVercelに買収されました。増分ビルドリモートキャッシュという2つの中核技術で、上記の問題を解決します。

a. 増分ビルドとタスクパイプライン

Turborepoでは、ルートのturbo.jsonファイルでタスク間の依存関係を定義できます。

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    },
    "dev": {
      "cache": false
    }
  }
}
  • dependsOn: ["^build"]^記号は、あるパッケージのbuildタスクが、そのパッケージの依存先にあるすべてのbuildタスクに依存することを意味します。Turborepoはこのグラフに基づき、最も効率的な並列順序でタスクを実行します。
  • outputs:そのタスクがどの出力ファイルを生成するかをTurborepoに伝えます。

pnpm turbo buildを実行すると、Turborepoは変更されたファイルを計算し、影響を受けたパッケージだけを再ビルドします。パッケージのソースコードと依存関係が変わっていなければ、Turborepoは前回のビルド成果物をそのまま使うため、処理は一瞬です。

b. リモートキャッシュ

これはTurborepoの「キラー機能」です。ローカルマシンにビルド結果をキャッシュするだけでなく、Vercelや独自のS3バケットなど、共有リモートサーバーへキャッシュをアップロードできます。

つまり、次のことが可能です。

  • 同僚が最新のコードを取得した後、その人が必要とする部分をあなたがすでにビルドしていれば、ローカルで再ビルドせずにキャッシュを直接ダウンロードできます。
  • CI/CDサーバーもこのリモートキャッシュに接続できます。あるPRがCIでビルドされキャッシュされれば、他の開発者や後続のCIタスクがその成果をすぐに利用できます。

これにより、チーム全体のビルド時間を数十分から数分、さらには数十秒まで短縮できます。

結論

TurborepoがMonorepoを発明したわけではありませんが、高度なキャッシュとタスクスケジューリングシステムを導入することで、Monorepoの開発体験を大幅に改善し、最も重要な性能上のボトルネックを解決しました。Monorepoアーキテクチャを使用している、または採用を考えているなら、Turborepoはあなたとチームの多くの時間を節約できる強力なツールです。