フルスタックプロジェクトのためのCI/CD最適化:Turborepoのリモートキャッシュとオンデマンドビルドの活用
Lukas Schneider
DevOps Engineer · Leapcell

はじめに
現代のフルスタックJavaScriptアプリケーションはますます複雑化しており、複数の相互依存サービス、フロントエンドアプリケーション、共有ライブラリを管理するためにモノレポアーキテクチャを採用することが一般的になっています。モノレポは、コード共有と依存関係管理の簡素化という点で大きな利点を提供しますが、特に継続的インテグレーション/継続的デリバリー(CI/CD)パイプラインにおいて、課題をもたらす可能性もあります。一般的なボトルネックは、コミットごとにコードベースの変更されていない部分を再構築するのに無駄になる時間とリソースです。1つのフロントエンドアプリでの小さなCSSの変更が、モノレポ内のすべてのサービスとアプリケーションの完全な再構築と再テストを引き起こすシナリオを想像してみてください。これは非効率的であるだけでなく、クラウドリソースと開発者の待ち時間という点でコストもかかります。この記事は、Turborepoの強力なリモートキャッシュとオンデマンドビルドの組み合わせが、フルスタックJavaScriptプロジェクトのCI/CDプロセスを劇的に最適化し、より高速なフィードバックループとインフラストラクチャコストの削減を保証する方法を探ることで、これらの課題に対処することを目的としています。
コアコンセプトと実装
最適化の詳細に入る前に、Turborepoの効果の中核となる概念を明確に理解しましょう。
モノレポとは?
モノレポとは、複数の個別のプロジェクトを含む単一のリポジトリであり、しばしば共有依存関係と構成を持ちます。典型的なフルスタックJavaScriptセットアップでは、これにはReactフロントエンド、Node.jsバックエンドAPI、共通UIコンポーネント、ユーティリティライブラリなどが含まれ、すべて同じGitリポジトリ内に配置されます。
Turborepoとは?
Turborepoは、JavaScriptおよびTypeScriptモノレポ向けの高性能ビルドシステムです。インテリジェントにビルド成果物をキャッシュし、必要なものだけを再構築することで、開発およびCI/CDエクスペリエンスを最適化するように設計されています。
Turborepoの主要機能
私たちの議論に特に役立つ2つの機能があります。
- リモートキャッシュ(Remote Caching):Turborepoは、ビルド成果物(コンパイル済みコード、テスト結果、バンドルされたアセットなど)をリモートキャッシュに保存できます。このキャッシュは、複数の開発者とCI/CDパイプラインで共有できます。特定のプロジェクトの特定のタスク(
build
やtest
など)が、同じ入力で以前に実行されたことがある場合、Turborepoはタスクを再実行する代わりにキャッシュされた出力を取得できます。 - オンデマンドビルド(On-Demand Builds / Incremental Builds):Turborepoは、モノレポの依存関係グラフを分析し、どのプロジェクトとタスクが変更の影響を受けているかを判断します。その後、影響を受けたプロジェクトのタスクのみを実行し、影響を受けていないプロジェクトはスキップします。これにより、冗長な作業を回避することで、ビルド時間が大幅に短縮されます。
Turborepoの設定
まず、モノレポにTurborepoを設定する必要があります。モノレポのルート、およびワークスペースパッケージ(例:apps/web
、packages/ui
)内の個別のpackage.json
ファイルがあることを前提とします。
// root package.json { "name": "my-fullstack-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "apps/*", "packages/*" ], "scripts": { "build": "turbo run build", "dev": "turbo run dev --parallel", "test": "turbo run test" }, "devDependencies": { "turbo": "^LatestVersion" } }
次に、パイプラインタスクとそのキャッシング動作を定義するために、モノレポのルートにあるturbo.json
ファイルを構成します。
// turbo.json { "$schema": "https://turbo.build/schema.json", "globalDependencies": [ "**/.env" // 例:.envファイルの変更はキャッシュを無効にします ], "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**"], "cache": true }, "test": { "dependsOn": [], "outputs": ["coverage/**"], "cache": true }, "lint": { "outputs": [] }, "dev": { "cache": false, // 開発サーバーは通常長時間実行されるため、キャッシングは不要です "persistent": true } } }
このturbo.json
では:
build
:^build
に依存しており、現在のパッケージの依存関係を最初にビルドすることを意味します。dist/**
と.next/**
の出力ディレクトリをキャッシュします。test
:テストの特定のプロジェクト依存関係はありませんが、テストを実行します。coverage/**
をキャッシュします。build
とtest
のcache: true
により、Turborepoのキャッシングメカニズムが有効になります。
リモートキャッシュの実装
Turborepoは、専用のTurborepoリモートキャッシュサービス(Vercelの製品またはセルフホスト型)への暗号化されたネットワーク接続を介してリモートキャッシュをサポートしています。
-
Vercel統合(最も簡単な方法):モノレポがVercelでホストされている場合、リモートキャッシュはほぼ自動で行われます。TurborepoをVercelチームとリンクするだけで、Vercelのリモートキャッシュが使用されます。
-
セルフホスト(AWS S3、Google Cloud Storageなど):セルフホストするには、環境変数を構成する必要があります。AWS S3の場合:
# これらの環境変数をCI/CD環境に設定します TURBO_REMOTE_CACHE_SIGNATURE_KEY="your-secret-key-for-signing-cache-requests" TURBO_REMOTE_CACHE_API="https://my-self-hosted-cache-endpoint.com" # または直接S3 URL TURBO_REMOTE_CACHE_READ_ONLY=false # 一部のCIステージでは読み取り専用アクセスにtrueに設定します
また、S3のようなストレージプロバイダーを使用して、TurborepoのリモートキャッシュAPIを実装するバックエンドサービスが必要になります。Turboは、これのためのオープンソースの例とツールを提供しています。
CI/CDワークフローの例(GitHub Actions):
# .github/workflows/ci.yml name: CI on: push: branches: - main pull_request: branches: - main jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: 18 - name: Install dependencies run: npm install # または yarn install / pnpm install - name: Turborepo Remote Cache configuration env: TURBO_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Vercel Remote Cacheを使用する場合 TURBO_TEAM: your-vercel-team-id # Vercel Remote Cacheを使用する場合 # またはセルフホストの場合: # TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} # TURBO_REMOTE_CACHE_API: ${{ secrets.TURBO_REMOTE_CACHE_API }} run: | # 環境変数が設定されている場合、または`vercel link`を介してVercelとリンクされている場合、 # このコマンドは自動的にリモートキャッシュに接続します echo "Configuring Turborepo for remote caching..." - name: Build affected projects run: npm run build # これは `turbo run build` を呼び出します # Turborepoはここで自動的にリモートキャッシュを利用します。 # プロジェクトのビルドがキャッシュされている場合、復元されます。 # そうでない場合、ビルドしてから出力をキャッシュに保存します。 - name: Test affected projects run: npm run test # これは `turbo run test` を呼び出します # ビルドと同様に、ビルドはキャッシュを利用します。
オンデマンドビルドの実際
Turborepoのオンデマンドビルド機能は、リモートキャッシュとうまく連携します。turbo run build
またはturbo run test
を実行すると、Turborepoは次の手順を実行します。
- グラフ分析(Graph Analysis):モノレポの依存関係グラフを構築します。
- フィンガープリント(Fingerprinting):各タスク(例:
apps/web
のbuild
)について、タスクの入力(ソースファイル、依存関係、環境変数、turbo.json
設定など)に基づいて一意の「フィンガープリント」を計算します。 - キャッシュルックアップ(Cache Lookup):まずローカルキャッシュで、次にリモートキャッシュで、このフィンガープリントが存在するかどうかを確認します。
- 実行または復元(Execution or Restoration):
- キャッシュヒットが発生した場合、キャッシュから出力を復元し、タスクを
cache hit
としてマークします。 - キャッシュヒットがない場合、タスクを実行し、その出力をローカルキャッシュとリモートキャッシュの両方に保存します。
- キャッシュヒットが発生した場合、キャッシュから出力を復元し、タスクを
- 影響を受けるプロジェクト(Affected Projects):変更を加えると、Turborepoはその変更に直接的または間接的に影響を受けるプロジェクトのみを再フィンガープリントし、再評価します。影響を受けないプロジェクトは、タスクが完全にキャッシュされている可能性が高いです。
実践的な例:
モノレポにapps/web
(Reactアプリ)とpackages/ui
(共有UIコンポーネント)があるとします。
apps/web
のファイルを変更した場合:apps/web
のbuild
およびtest
タスクのみが実行される可能性があります。packages/ui
のタスクはキャッシュから取得されます。packages/ui
のファイルを変更した場合:packages/ui
のタスクとapps/web
のタスク(apps/web
はpackages/ui
に依存しているため)の両方が実行される可能性があります。他の無関係なプロジェクトはキャッシュから取得されます。
このインテリジェントなオーケストレーションは、CI/CDパイプラインがコミットごとにすべてを再構築する必要がなくなることを意味し、実行時間の劇的な短縮とリソース消費の削減につながります。
結論
Turborepoのリモートキャッシュとオンデマンドビルドは、CI/CDにおけるフルスタックJavaScriptモノレポの管理方法を根本的に変革します。ビルド成果物をインテリジェントに保存および取得し、影響を受けるタスクのみを選択的に実行することで、Turborepoは冗長な作業を排除し、ビルド時間とCI/CDコストを大幅に削減します。Turborepoを採用することは、開発サイクルの加速とフルスタックモノレポワークフローの効率向上を目指すチームにとって、戦略的な一歩となります。