モノレポでのタスクの実行
すべてのモノレポには、ワークスペースとタスクの2つの主要な構成要素があります。3つのワークスペースがあり、それぞれに3つのタスクが含まれているモノレポがあると想像してみましょう。
ここでは、apps/web
とapps/doc
の両方がpackages/shared
のコードを使用します。実際、それらがビルドされるとき(build
経由)、packages/shared
が最初にビルドされる必要があります。
ほとんどのツールは速度を最適化しない
すべてのワークスペースで、すべてのタスクを実行したいとしましょう。yarn
のようなツールでは、次のようなスクリプトを実行する可能性があります。
yarn workspaces run lint
yarn workspaces run test
yarn workspaces run build
これは、タスクがこのように実行されることを意味します。
ご覧のとおり、lint
はすべてのワークスペースで実行されます。次に、build
が実行され、shared
が最初に実行されます。最後に、test
が実行されます。
これは、これらのタスクを実行する最も遅い方法です。各タスクは、開始する前に前のタスクが完了するのを待つ必要があります。これを改善するには、マルチタスクが可能なツールが必要になります。
Turborepo はマルチタスクが可能
Turborepo は、タスク間の依存関係を理解することで、タスクを最大速度でスケジュールできます。
まず、turbo.json
内にタスクを宣言します。
{
"$schema": "https://turbo.dokyumento.jp/schema.json",
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"],
// ^build means `build` must be run in dependencies
// before it can be run in this workspace
"dependsOn": ["^build"]
},
"test": {},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
次に、yarn workspaces
スクリプトを次のように置き換えることができます。
- yarn workspaces run lint
- yarn workspaces run test
- yarn workspaces run build
+ turbo run lint test build
これを実行すると、Turborepo は使用可能なすべての CPU で可能な限り多くのタスクをマルチタスクで実行するため、タスクは次のように実行されます。
lint
と test
は、turbo.json
で dependsOn
が指定されていないため、すぐに実行されます。
shared
内の build
タスクが最初に完了し、その後 web
と docs
のビルドが続きます。
パイプラインの定義
pipeline
設定は、モノレポ内でどのタスクが互いに依存しているかを宣言します。以下は包括的な例です。
{
"$schema": "https://turbo.dokyumento.jp/schema.json",
"pipeline": {
"build": {
// A workspace's `build` task depends on that workspace's
// topological dependencies' and devDependencies'
// `build` tasks being completed first. The `^` symbol
// indicates an upstream dependency.
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
},
"deploy": {
// A workspace's `deploy` task depends on the `build`,
// `test`, and `lint` tasks of the same workspace
// being completed.
"dependsOn": ["build", "test", "lint"]
},
"test": {
// A workspace's `test` task depends on that workspace's
// own `build` task being completed first.
"dependsOn": ["build"],
// A workspace's `test` task should only be rerun when
// either a `.tsx` or `.ts` file has changed.
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
},
// A workspace's `lint` task has no dependencies and
// can be run whenever.
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
タスクの設定方法の詳細については、次のセクション「タスクの依存関係」を参照してください。
ルートからのタスク実行
turbo
は、モノレポのルートにある package.json
ファイルに存在するタスクを実行できます。これらは、キー構文 "//#<task>"
を使用して、パイプライン設定に明示的に追加する必要があります。これは、すでに独自のエントリを持つタスクの場合でも同様です。たとえば、パイプラインが "build"
タスクを宣言しており、モノレポのルート package.json
ファイルで定義されている build
スクリプトを turbo run build
で含めたい場合は、設定で "//#build": {...}
を宣言して、ルートをオプトインする必要があります。逆に、必要なのが "//#my-task": {...}
だけの場合は、一般的な "my-task": {...}
エントリを定義する必要はありません。
ルートタスク format
を定義し、ルートを test
にオプトインするサンプルパイプラインは、次のようになります。
{
"$schema": "https://turbo.dokyumento.jp/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", ".svelte-kit/**"]
},
"test": {
"dependsOn": ["^build"],
},
// This will cause the "test" script to be included when
// "turbo run test" is run
"//#test": {
"dependsOn": [],
},
// This will cause the "format" script in the root package.json
// to be run when "turbo run format" is run. Since the general
// "format" task is not defined, only the root's "format" script
// will be run.
"//#format": {
"dependsOn": [],
"outputs": ["dist/**/*"],
"inputs": ["version.txt"]
}
}
}
再帰に関する注意:モノレポのルート package.json
で定義されたスクリプトは、多くの場合、turbo
自体を呼び出します。たとえば、build
スクリプトは turbo run build
である可能性があります。この状況では、turbo run build
に //#build
を含めると、無限再帰が発生します。このため、モノレポのルートから実行されるタスクは、パイプライン設定に //#<task>
を含めることによって、明示的にオプトインする必要があります。turbo
には、再帰的な状況でエラーを生成するためのベストエフォートチェックがいくつか含まれていますが、再帰を引き起こす turbo
の実行をトリガーしないタスクのみをオプトインするのはユーザーの責任です。
段階的な導入
turbo.json
でタスクを宣言した後、package.json
マニフェストでそれを実装するのはユーザーの責任です。スクリプトは一度にすべて追加することも、一度に1つのワークスペースずつ追加することもできます。Turborepoは、それぞれの package.json マニフェストにタスクが含まれていないワークスペースを適切にスキップします。
たとえば、リポジトリに3つのワークスペースがある場合(上記のワークスペースと同様)
apps/
web/package.json
docs/package.json
packages/
shared/package.json
turbo.json
package.json
ここで、turbo.json
が build
タスクを宣言しているが、2つの package.json
のみがその build
タスクを実装している場合
{
"$schema": "https://turbo.dokyumento.jp/schema.json",
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
}
}
}
turbo run build
turbo のビルドでは、web
および docs
ワークスペースに対してのみ build
スクリプトが実行されます。shared
パッケージは引き続きタスクグラフの一部になりますが、適切にスキップされます。
Turborepo のパイプライン API 設計とこのドキュメントのページは、Microsoft の Lage プロジェクト (新しいタブで開きます) に着想を得ています。このような簡潔でエレガントな方法でタスクを展開するというアイデアをくれた Kenneth Chau (新しいタブで開きます) に感謝します。