turbo/genの基本機能とTurborepoモノレポ開発で果たす役割の全体像
目次
turbo/genの基本機能とTurborepoモノレポ開発で果たす役割の全体像
turbo/genは、Vercelが開発するモノレポビルドシステムTurborepoに組み込まれたコード生成機能です。新しいパッケージやコンポーネントを定型的に追加する作業を自動化し、リポジトリ全体の一貫性を保つ役割を担います。まずは全体像として、解決する課題と提供される機能の種類、コマンド体系を整理していきましょう。
turbo/genが解決するモノレポ特有のボイラープレート増殖という課題
モノレポでは複数のアプリケーションとパッケージを単一リポジトリで管理するため、新規ワークスペースを追加するたびにpackage.jsonやtsconfig.json、ESLint設定などの定型ファイルを用意する必要があります。手作業でこれらを準備すると、既存パッケージからのコピー漏れや依存バージョンの不一致が発生しやすくなります。パッケージ数が増えてくると、設定の微妙な差異が積み重なり、ビルドエラーの原因特定に時間を奪われることも珍しくありません。
turbo/genはこの問題に対し、テンプレートに基づいた予測可能な生成という解決策を提供します。生成されるファイルの構成や依存関係の追加が定義ファイルで管理されるため、誰が実行しても同じ構造のコードが得られます。属人化しがちだった「新規パッケージの正しい作り方」がコードとして明文化される点こそ、このツールの本質的な価値です。生成手順そのものがレビュー可能な資産として残る点も、長期運用では見逃せない利点です。
Plopベースのテンプレートエンジンが提供する3種類の組み込み生成機能
turbo/genの内部はJavaScriptエコシステムで広く使われるテンプレート定義ツールPlop(node-plop)の上に構築されています。提供される生成機能は大きく分けて次の3種類です。
| 生成タイプ | 概要 | 主な用途 |
|---|---|---|
| empty | 空のワークスペースを新規作成 | ゼロから設計する新規パッケージ |
| copy | 既存ワークスペースを複製して作成 | 既存構成を踏襲したパッケージ追加 |
| custom | 独自定義のジェネレーターを実行 | コンポーネント等の細かい単位の生成 |
emptyとcopyはワークスペース単位の生成に特化しており、対話形式の質問に答えるだけで利用できます。一方customは、Plopの設定ファイルに独自のプロンプトとアクションを記述することで、ファイル単位の細かなコード生成まで自由に設計できる仕組みです。この3種類を場面に応じて使い分けることが、turbo/gen活用の出発点になります。迷ったときは、まず生成したい単位がワークスペース全体か否かという基準で選ぶと判断しやすいでしょう。
turbo generateコマンドとturbo genエイリアスの関係と実行時の動作
コマンドラインでの正式名称はturbo generateですが、短縮形としてturbo genというエイリアスが用意されており、両者は完全に同じ動作をします。さらにgenerateコマンドのデフォルトサブコマンドはrunであるため、turbo genと入力するだけでturbo generate runを実行した場合と同じくカスタムジェネレーターの実行が始まります。日常的な操作では短いエイリアスを使うのが一般的でしょう。
実行するとリポジトリ内のジェネレーター設定が検索され、複数定義されている場合は対話形式で選択肢が表示されます。実行したいジェネレーター名が決まっているなら、turbo gen [ジェネレーター名]と引数で直接指定すれば選択ステップの省略が可能です。CIやスクリプトから呼び出す場合は、この引数指定と–argsオプションによる回答の事前指定を組み合わせると非対話で完結します。繰り返し実行する定型作業ほど、この短縮形と引数指定の恩恵は大きくなるはずです。
@turbo/genパッケージが提供するPlopTypes型定義の役割と利用場面
npmで公開されている@turbo/genパッケージは、カスタムジェネレーターの設定ファイルをTypeScriptで型安全に記述するための型定義を提供します。開発依存としてpnpm add @turbo/gen --save-devのようにインストールし、設定ファイル内でimport type { PlopTypes } from "@turbo/gen"と読み込んで利用する流れです。これによりsetGeneratorに渡すprompts、actionsの構造がエディタ上で補完され、定義ミスを実行前に検出できるようになります。
型定義にはPlop本体のAPIに加え、Turborepoが実行時に注入するturboオブジェクトの構造も含まれています。リポジトリのルートパスやturbo.jsonの設定情報へ型安全にアクセスできるため、リポジトリ構造に依存した高度なジェネレーターを書く場面で特に効果を発揮するでしょう。JavaScriptで設定を書く場合は必須ではありませんが、保守性を考えるとTypeScriptと型定義の併用が推奨されます。
Turborepo 1.10で導入された経緯と現行バージョンまでの機能拡張の流れ
コードジェネレーター機能は2023年6月リリースのTurborepo 1.10で正式に導入されました。それ以前は新規ワークスペースの追加にあたり、開発者自身がコードをコピーし依存関係を手動で追加する必要があり、この作業の自動化が導入の主な動機として公式ブログで説明されています。導入当初からワークスペースの新規作成、既存複製、Plop設定によるカスタム生成という現在の基本構成が揃っていました。
その後Turborepo本体は2.x系へとメジャーバージョンアップし、@turbo/genパッケージも本体に追従する形で更新が続いています。実行時に注入されるturboオブジェクトの情報拡充など、カスタムジェネレーターから参照できるコンテキストは段階的に強化されてきました。導入時期の古い記事ではコマンド体系や設定の細部が現行版と異なる場合があるため、公式ドキュメントの最新版を基準に確認する姿勢が重要です。公式の更新履歴を定期的に追う習慣こそ、設定の手戻りを防ぐ確実な近道になります。
turbo gen workspaceとカスタムジェネレーターの機能差と使い分け基準
turbo/genには、ワークスペース単位の生成を担うworkspaceサブコマンドと、自由度の高いカスタムジェネレーターという2つの柱があります。両者は生成の粒度と設定コストが大きく異なるため、特徴を理解して使い分けることが効率化の鍵です。ここでは適用場面と判断基準を具体的に整理します。
turbo gen workspaceによる空ワークスペース新規作成の適用場面
turbo gen workspaceを実行すると、対話形式の質問に答えるだけで新しいアプリまたはパッケージの雛形がモノレポ内に追加されます。名前や種類(appかpackageか)、配置先ディレクトリなどを順に答えると、package.jsonを備えた空のワークスペースが作成され、リポジトリのワークスペース定義にも組み込まれます。事前の設定ファイル作成が一切不要なため、導入初日からすぐに使える点が大きな利点です。
適しているのは、既存パッケージの構成にとらわれず新しい設計で始めたい場合や、実験的なパッケージを素早く切り出したい場面です。一方で生成されるのは最小限の骨組みであり、tsconfigやビルド設定などは自分で整える必要があります。社内標準の構成を毎回再現したい場合には、後述するcopyオプションやカスタムジェネレーターの方が適しているでしょう。まずは試験的なパッケージで一度実行し、生成される雛形の範囲を体感しておくと判断が早まります。設定不要という手軽さは、他の手段にはない明確な強みです。
–copyオプションで既存パッケージを複製する際の依存関係の引き継ぎ範囲
turbo gen workspace --copyを使うと、リポジトリ内の既存ワークスペースをテンプレートとして新しいワークスペースを作成できます。コピー元のファイル一式が新しい名前で複製されるため、tsconfigやESLint設定、ディレクトリ構造といった社内標準の構成をそのまま引き継げます。package.jsonに記載された依存関係も複製されるので、ゼロから依存を追加し直す手間がかかりません。
ただし複製はあくまでコピー元の時点の内容が基準であり、コピー後にパッケージ名の参照やREADMEの記述など、名称に依存する箇所の手直しが必要になる場合があります。とくにリモートからの複製では、必要な依存関係やパッケージマネージャーの整合性をTurborepoが検証できず、手動での修正が必要になる場合があると公式ドキュメントに明記されています。複製後は依存のインストールと動作確認まで済ませてから開発を始めるのが安全です。コピー元として使う「お手本パッケージ」を常に最新の標準構成に保っておく運用も、品質維持の観点で効果的でしょう。複製機能は万能ではなく、複製後の微修正までを一連の手順として捉えることが大切です。
GitHub URL指定でリモートリポジトリからテンプレートを取得する活用例
copyオプションの強力な点は、複製元として自リポジトリ内のワークスペースだけでなく、GitHub上のリモートリポジトリを指定できることです。たとえば次のように実行すると、Turborepo公式サンプルの設定パッケージを自分のモノレポへ取り込めます。
turbo gen workspace --copy https://github.com/vercel/turborepo/tree/main/examples/with-tailwind/packages/tailwind-config
この仕組みは、公式や他チームが公開しているベストプラクティス構成を出発点にしたい場合に有効です。Tailwind設定やESLint共有設定のような汎用パッケージを取り込み、自社向けに調整していく進め方なら、設計の初期コストを大幅に削減できます。複数のリポジトリを運営する組織では、社内の参照リポジトリにテンプレート用パッケージを集約しておき、各リポジトリからURL指定で取り込む運用も現実的な選択肢になるでしょう。
カスタムジェネレーターがファイル単位の生成に適している判断基準
workspaceサブコマンドの生成単位はあくまでワークスペース全体ですが、実際の開発で頻度が高いのはUIコンポーネント1つ、APIルート1本といったより細かい単位の追加です。このような粒度の生成にはカスタムジェネレーターが適しています。Plop形式の設定ファイルにプロンプトとアクションを記述することで、複数ファイルの同時生成や既存ファイルへの追記まで自由に設計できるためです。
使い分けの判断基準は「生成対象がワークスペースか、その内部のコードか」というシンプルな軸で考えると迷いません。さらに、同じ構造のファイル群を月に数回以上作っているなら、カスタムジェネレーター化の設定コストは十分回収できます。逆に年に1、2回しか発生しない作業であれば、copyオプションや手作業で済ませる判断も合理的です。生成の頻度と定型度の2軸で評価しましょう。頻度が高く構造が安定している作業から優先的にジェネレーター化すると、投資効果を実感しやすくなります。小さく始めて徐々に対象を広げる進め方が定着の近道です。
両機能を組み合わせてUIコンポーネント量産体制を構築する実務パターン
実務で効果が大きいのは、workspace機能とカスタムジェネレーターを段階的に組み合わせるパターンです。まずcopyオプションで標準構成のUIパッケージを作成し、その内部にコンポーネント生成用のカスタムジェネレーターを定義します。以後、新しいボタンやフォーム部品が必要になるたびにturbo genを実行すれば、コンポーネント本体とテストファイル、エクスポート文の追記までが一括で完了する体制が整います。
この体制ではコンポーネントの構造が常に統一されるため、Storybookの追加やテスト方針の変更といった横断的な改修も見通しよく進められます。デザインシステムを運用するチームであれば、命名規則やディレクトリ規約をジェネレーターに織り込むことで、レビューで指摘される表記ゆれを生成段階で排除できます。量産フェーズに入る前にこの基盤を整えておくことが、後工程の品質を大きく左右するでしょう。立ち上げ時の数時間の投資が、その後の数百回の生成作業で回収される構図です。
手作業コピーやHygen等の他手法と比較したturbo/gen採用の判断材料
コード生成の手段はturbo/genだけではありません。手作業のコピーや汎用ジェネレーターのHygen、Plop単体の利用、自作スクリプトなど複数の選択肢があります。この章では各手法との違いを比較し、turbo/genを採用すべきケースと見送るべきケースの判断材料を提示します。
手作業コピーで発生する依存関係の追加漏れと設定不整合の失敗パターン
最も手軽に見える「既存パッケージをフォルダごとコピーして書き換える」方法には、再現性の低さという根本的な弱点があります。典型的な失敗は、package.jsonのname書き換え漏れによるワークスペース名の衝突、コピー元にだけ存在した依存パッケージの消し忘れ、tsconfigのパス参照が旧名称のまま残る不整合などです。これらはビルドが通ってしまう場合もあり、後日まったく別の作業中に原因不明のエラーとして表面化することがあります。
さらに深刻なのは、コピー手順が人によって微妙に異なるため、リポジトリ内に「正しい構成」が複数並立してしまう状態です。一度この状態に陥ると、どのパッケージを手本にすべきか判断できなくなり、修正コストは時間とともに膨らみます。月に複数回の追加作業が発生するリポジトリでは、手作業の継続自体がリスクと考えるべきでしょう。失敗の原因は個人の注意力不足ではなく、手順が仕組み化されていないこと自体にあります。早期の自動化こそが傷を浅く抑える唯一の現実解です。
HygenやPlop単体利用と比較したturbo情報自動注入の優位性
汎用のコード生成ツールとしてはHygenやPlopが有名で、どちらもTurborepoと無関係に利用できます。テンプレート機能の表現力という点では大きな差はありませんが、turbo/genにはTurborepo統合ならではの優位性があります。主要な違いを次の表に整理しました。
| 観点 | turbo/gen | Plop単体 | Hygen |
|---|---|---|---|
| テンプレート記法 | Handlebars | Handlebars | EJS |
| リポジトリ情報の注入 | turboオブジェクトを自動注入 | なし(自前実装) | なし(自前実装) |
| ワークスペース生成 | 組み込みコマンドあり | 自前実装 | 自前実装 |
| 導入コスト | Turborepo利用なら追加設定最小 | 個別セットアップ | 個別セットアップ |
最大の差別化要素は、実行時にリポジトリのルートパスやturbo.json設定などを含むturboオブジェクトが回答データへ自動注入される点です。汎用ツールではこれらの情報収集ロジックを自分で書く必要がありますが、turbo/genなら最初から利用できます。すでにTurborepoを使っているなら、あえて別ツールを併用する理由は限られるでしょう。
create-turboとの役割分担から見るリポジトリ初期化後の使い分け基準
Turborepoには、リポジトリそのものを新規作成するcreate-turboというツールも存在し、turbo/genと混同されがちです。両者の役割分担は明確で、create-turboはモノレポの初期構築を一度だけ担うのに対し、turbo/genは構築済みリポジトリの内部に継続的にコードを追加していく日常運用のツールです。利用タイミングが時系列で重ならないと理解すると整理しやすいでしょう。
判断基準としては、リポジトリが存在しない段階ならcreate-turboで公式サンプルから出発し、その後のパッケージ追加やコンポーネント追加はすべてturbo/genへ移行するのが標準的な流れです。create-turboのサンプルには構成の整ったパッケージが含まれるため、それらをcopyオプションの複製元として活用すると、初期化から量産体制への移行が滑らかになります。2つのツールを連続したパイプラインとして捉える視点が有効です。役割の境界を理解しておくと、ツール選定の議論で迷う時間を減らせます。
シェルスクリプト自作と比較した保守コストと学習コストの損益分岐点
cpコマンドとsedによる置換を組み合わせた自作シェルスクリプトでも、単純な生成なら実現できます。初期実装は数時間で済むことが多く、学習コストもほぼゼロという利点は無視できません。しかし対話的な入力の検証、生成先の存在チェック、既存ファイルへの安全な追記といった要件が加わるたびにスクリプトは複雑化し、保守できる人が書いた本人だけという属人化が進みがちです。
損益分岐点の目安は、生成パターンの数と変更頻度で考えられます。生成対象が1種類で構成変更もほぼないなら自作スクリプトで十分ですが、パターンが3種類を超えるか、テンプレートの更新が四半期に一度以上発生するなら、宣言的に管理できるturbo/genの方が総コストは低くなります。チームメンバーの入れ替わりが想定される組織では、公式ドキュメントが存在するツールを選ぶこと自体が保守コストの削減につながるでしょう。迷う場合は、スクリプトの行数が100行を超えた時点を移行検討の合図とする目安も実用的です。
導入を見送るべきケースの判断基準となるリポジトリ規模と更新頻度
turbo/genは万能ではなく、導入を見送る判断が合理的なケースもあります。第一に、そもそもTurborepoを採用していない単一パッケージのリポジトリでは、turboオブジェクト注入などの統合機能が活きないため、PlopやHygenを直接使う方が素直です。第二に、パッケージ数が2、3個で今後も増える見込みがない小規模構成では、テンプレート整備の初期投資を回収できない可能性が高いといえます。
また、生成したいコードの構造が案件ごとに大きく異なり定型化が困難な場合も、無理にテンプレート化すると条件分岐だらけの複雑な定義になり逆効果です。判断の目安として、同一構造のコード追加が月1回未満、かつ関与する開発者が2名以下であれば、手作業とレビューで品質を担保する運用でも破綻しにくいでしょう。導入そのものを目的化せず、作業頻度と人数から必要性を見極める姿勢が重要です。条件が変わって頻度が上がった時点で導入を再検討すれば十分間に合います。撤退基準を先に決めておく運用も有効でしょう。
turbo/gen導入からカスタムジェネレーター作成までの具体的な実装手順
ここからは実際に手を動かす工程です。パッケージのインストールから設定ファイルの作成、プロンプトとアクションの実装、テンプレート変数の活用、動作検証までを順に解説します。この章の手順を一通り終えれば、自分のモノレポで独自ジェネレーターが動く状態になります。
pnpm add -D @turbo/genによるインストールと前提環境の確認手順
カスタムジェネレーターをTypeScriptで記述するため、まず型定義を提供する@turbo/genパッケージを開発依存として追加します。導入は次の流れで進めると確実です。
- Turborepo本体(turboパッケージ)がインストール済みであることをpackage.jsonで確認する
- リポジトリのルートまたは対象ワークスペースでpnpm add @turbo/gen –save-devを実行する
- turbo gen –helpを実行し、generateコマンドが認識されることを確認する
npmやyarnを使っている場合も、各ツールの開発依存追加コマンドに読み替えるだけで手順は同じです。注意点として、@turbo/genが提供するのは主にTypeScript用の型定義であり、内部基盤であるPlop自体を依存関係として追加する必要はないと公式ドキュメントで明記されています。本体のバージョンが極端に古いとジェネレーター機能自体が存在しないため、1.10未満を使っている場合は先に本体の更新を済ませておきましょう。導入に必要な作業は基本的にこの3手順だけで、追加の初期設定はほとんど発生しません。
config.tsに記述するsetGenerator定義の基本構成と必須要素
カスタムジェネレーターの定義ファイルは、リポジトリ内のturbo/generators/config.tsに配置するのが基本です。ファイルはPlopのAPIを受け取る関数をデフォルトエクスポートする形式で記述します。最小構成は次のようになります。
import type { PlopTypes } from "@turbo/gen"; export default function generator(plop: PlopTypes.NodePlopAPI): void { plop.setGenerator("component", { description: "UIコンポーネントを生成", prompts: [], actions: [] }); }
必須要素は、setGeneratorの第1引数となるジェネレーター名、概要を示すdescription、入力を定義するprompts、生成処理を定義するactionsの4つです。1つのconfig.tsに複数のsetGeneratorを記述でき、その場合は実行時に対話形式で選択できます。各ワークスペースのディレクトリ配下にも同じ構造で設定を置けるため、パッケージ固有のジェネレーターはそのパッケージ内に定義すると見通しが良くなるでしょう。
promptsで対話的に入力を受け取りactionsでファイルを生成する実装例
promptsには質問の配列を定義します。たとえばコンポーネント名を尋ねるなら、type: “input”、name: “name”、message: “コンポーネント名は?”というオブジェクトを1件追加するだけで、実行時に対話プロンプトが表示されます。回答はnameで指定したキーに格納され、後続のactionsから参照できる仕組みです。validateプロパティで入力検証関数を指定すれば、空文字や命名規則違反をその場で弾けます。
actionsで最も使うのは、テンプレートから新規ファイルを作るaddアクションです。path: “src/components/{{ pascalCase name }}.tsx”、templateFile: “templates/component.hbs”のように生成先とテンプレートを指定します。既存ファイルへ行を追記するappendやmodifyといったアクションも用意されており、エクスポート文の自動追加などに活用できます。複数アクションを配列に並べれば、本体・テスト・追記の3点セットを一度に処理できるでしょう。
Handlebarsテンプレート内で利用できる変数とturboオブジェクトの参照方法
テンプレートはHandlebars形式で記述し、promptsで受け取った回答を{{ name }}のような二重波括弧で埋め込みます。Plopには文字列変換ヘルパーが組み込まれており、pascalCaseやcamelCase、kebabCaseなどを組み合わせることで、1つの入力からクラス名・ファイル名・CSSクラス名を一貫した規則で展開できます。表記ゆれを根本から防げるため、これらのヘルパーは積極的に使うべき機能です。
さらにTurborepoはアクション実行時、回答データへturboオブジェクトを自動注入します。このオブジェクトからはリポジトリのルートパスやワークスペースの場所といった情報に加え、リポジトリ内で見つかったturbo.jsonおよびturbo.jsoncの設定内容へアクセスできます。生成先をリポジトリ構造から動的に決めたい場合や、タスク設定に応じてテンプレートを切り替えたい場合に、この注入情報が威力を発揮するでしょう。変数とヘルパーの組み合わせ方が、テンプレートの再利用性を決める核心部分です。
作成したジェネレーターをturbo genで実行し動作検証する確認手順
定義が完成したら、リポジトリのルートでturbo genを実行します。設定ファイルが正しく検出されていれば、定義したジェネレーターが選択肢に表示され、選択するとpromptsの質問が順番に始まります。すべて回答するとactionsが実行され、生成または変更されたファイルのパスが結果として表示されるため、まずはこの一覧が想定どおりかを確認しましょう。
検証で確認すべきポイントは3つあります。第一に、生成ファイルの配置先とファイル名が命名規則どおりであること。第二に、テンプレート変数がすべて展開され、波括弧の残骸が残っていないこと。第三に、生成直後のコードがlintと型チェックを通過することです。検証用の入力には、ハイフン入りや大文字始まりなど境界的な名前をあえて与えると、ヘルパーの変換漏れを早期に発見できます。問題があればconfig.tsとテンプレートを修正し、再実行で確認を繰り返します。この検証サイクルを丁寧に回した分だけ、チーム展開後の問い合わせは確実に減るでしょう。
turbo/gen運用で頻発する設定ミスとテンプレート設計の失敗回避策
turbo/genは導入自体が容易な反面、設定ファイルの配置やテンプレート設計には見落としやすい落とし穴があります。この章では、実運用で遭遇しやすい5つの失敗パターンを取り上げ、それぞれの原因と回避策を具体的に解説します。トラブル発生時の調査の手がかりとしても活用してください。
config.tsの配置場所誤りでジェネレーターが検出されない失敗パターン
「turbo genを実行してもジェネレーターが表示されない」という症状の原因として最も多いのが、設定ファイルの配置場所の誤りです。検出対象となる標準の場所はturbo/generators/config.tsであり、ディレクトリ名をgeneratorではなくgeneratorsと複数形にする点や、turboディレクトリ直下ではなくその中のgenerators配下に置く点を取り違えると検出されません。ルート用とワークスペース用で配置階層が異なることも混乱の一因です。
回避策としては、最初の1つを公式ドキュメントの記載どおりのパスへ正確に作成し、turbo genで表示されることを確認してから中身の実装に進む手順を徹底することです。検出されない場合は、まずディレクトリ名のスペルと階層を疑い、次にファイルがデフォルトエクスポートの関数になっているかを確認します。この2点だけで配置起因のトラブルの大半は解消できるでしょう。配置規約をREADMEに明記しておくと、再発防止にも役立ちます。
テンプレート内のパス指定ミスで生成先が意図とずれる典型的な設定ミス
addアクションのpathに相対パスを指定した際、基準となる位置の認識違いから、生成物が想定外のディレクトリに出力される問題も頻発します。とくにルートの設定とワークスペース内の設定が混在している場合、どちらの設定から実行されたかで基準位置が変わり、同じ定義でも生成先がずれることがあります。気づかないままコミットすると、誰も参照しないディレクトリにファイルが積み上がる事態になりかねません。
対策の基本は、pathの組み立てに推測を持ち込まず、検証で確かめることです。回答データに注入されるturboオブジェクトからルートパスを取得して絶対的な基準を作る方法は、実行位置の影響を受けにくく安定します。さらに、ジェネレーター追加時には必ずクリーンな作業ブランチで試し、git statusで生成物の位置を確認するルールを設けると、ずれの混入をコミット前に確実に検出できるでしょう。生成先の正しさは、テンプレートの中身の品質以前に満たすべき最低条件と捉えるのが妥当です。
ESMとCommonJSの混在で発生するconfig読み込みエラーの回避策
config.tsの読み込み時に発生するエラーの代表例が、モジュール形式の不一致に起因するものです。リポジトリのpackage.jsonでtype: “module”を指定してESMに統一している環境と、CommonJS前提の環境とでは、設定ファイルで許容される記法が異なります。requireとimportの混在や、tsconfigのmodule設定との食い違いがあると、ジェネレーター実行時に構文エラーや読み込み失敗として表面化します。
回避の原則は、設定ファイルの記法をリポジトリ全体のモジュール方針に合わせて統一することです。具体的には、公式ドキュメントのサンプルにあるimport type構文とexport defaultの組み合わせを基本形とし、独自のrequire呼び出しを持ち込まないようにします。エラーが出た場合は、メッセージに含まれるモジュール関連の文言を手がかりに、package.jsonのtype指定とtsconfigの設定を順に照合すると原因を特定しやすいでしょう。
カスタムアクションでの非同期処理を誤りビルドが壊れる失敗事例
actionsには組み込みアクションだけでなく、独自の関数を渡すカスタムアクションも定義できます。外部APIからデータを取得してテンプレートに渡すといった高度な使い方ができる一方、非同期処理の扱いを誤る事故が起きやすい箇所です。典型例は、async関数内のawait漏れにより取得完了前に後続アクションが走り、未定義値がテンプレートへ展開されて壊れたコードが生成されるケースです。生成直後は気づかず、ビルド段階で初めて発覚することもあります。
回避策は3点に集約されます。第一に、カスタムアクションは必ずasync関数として定義し、内部のPromiseをすべてawaitで解決してから状態文字列を返すこと。第二に、取得失敗時は例外を投げて生成を中断させ、不完全なファイルを残さないこと。第三に、取得結果をanswersへ格納する際はキー名の衝突を避け、後続アクションが参照する名前を定義内で明示することです。この規律だけで非同期起因の事故はほぼ防げます。同期処理と同じ感覚で書かないことが出発点です。
バージョン更新時にPlop APIの変更で既存定義が動かなくなる予防策
turbo/genは内部でnode-plopに依存しているため、Turborepo本体や@turbo/genのメジャー更新に伴って、依存するPlopのバージョンが変わることがあります。Plop側のAPIや型定義に非互換の変更が入ると、これまで動いていたconfig.tsが型エラーや実行時エラーを起こす可能性があります。更新作業をビルド設定の更新とまとめて行うと、原因の切り分けに余計な時間を取られがちです。
予防策の第一は、Turborepo関連パッケージの更新を独立したプルリクエストとして扱い、更新後に全ジェネレーターを一度ずつ実行して生成結果を確認する手順を組み込むことです。第二に、リリースノートと変更履歴を更新前に確認し、generator関連の記載があれば該当箇所を先に修正します。ジェネレーターの実行確認をCIに組み込み、サンプル入力で生成→lint→型チェックまで自動検証する体制があれば、互換性の問題を更新当日に検出できるでしょう。依存更新の影響範囲を小さく保つ工夫が、長期運用の安定につながります。
チーム開発でturbo/genを定着させる運用ルールと実務活用パターン
ジェネレーターは作って終わりではなく、チーム全員が使い続けてこそ価値を発揮します。最終章では、命名規則の強制やオンボーディング短縮、定義の共有、陳腐化の防止、レビュー運用といった、組織にturbo/genを定着させるための実践的なパターンを紹介します。
コンポーネント命名規則をpromptsのバリデーションで強制する運用例
チーム開発で頻出する「命名規則のレビュー指摘」は、ジェネレーターの入口で機械的に排除できます。promptsの各質問にはvalidate関数を設定でき、入力値が条件を満たさない場合にエラーメッセージを返して再入力を促せます。たとえばコンポーネント名に対し、英字始まりかつ英数字のみ、予約語と既存コンポーネント名の重複禁止といった検証を実装すれば、規則違反の名前はそもそも生成段階に進めません。
運用のコツは、エラーメッセージに正しい形式の具体例を含め、開発者がその場で修正できるようにすることです。さらにpascalCaseヘルパーによる変換と組み合わせれば、入力の揺らぎがあっても最終的な成果物は常に統一された表記になります。レビューで人間が指摘していた事項を仕組みへ移すことで、レビュアーは設計や仕様といった本質的な観点に集中できるようになるでしょう。検証ルールはジェネレーター定義ファイル内で一元管理されるため、命名規則を変更した際の反映漏れも起きにくい構造になっています。
新規メンバーのオンボーディング工数を削減するテンプレート整備の実務例
新規メンバーの立ち上がりで時間を消費するのは、コード規約やディレクトリ構成といった暗黙知の習得です。turbo/genのテンプレートにチームの標準構成を織り込んでおけば、入社初日のメンバーでもコマンド1つで「正しい形」のコードを作れます。お手本を探してリポジトリを巡回したり、先輩の過去コードを真似て古い書き方を引き継いだりする非効率を、仕組みで断ち切れる点が大きな利点です。
実務的には、最初のタスクとして「ジェネレーターで小さなコンポーネントを1つ追加する」課題を割り当てる方法が効果的です。生成されたコードを読むこと自体が規約の学習になり、プロンプトの質問文がそのまま設計時の確認事項のチェックリストとして機能します。テンプレート内に参考ドキュメントへのリンクをコメントで残しておくと、生成物が学習教材を兼ねる形になり、教育コストをさらに圧縮できるでしょう。立ち上がり期間の短縮効果は、採用人数が多い組織ほど大きく積み上がります。教育担当者の負荷軽減という副次効果も見逃せません。
ジェネレーター定義自体をパッケージ化して複数リポジトリで共有する方法
複数のモノレポを運営する組織では、各リポジトリで同じようなジェネレーター定義が重複しがちです。この重複は、テンプレートとプロンプト定義を独立したパッケージとして切り出し、各リポジトリのconfig.tsから読み込んで登録する構成で解消できます。config.tsはPlopのAPIを受け取る通常のTypeScript関数なので、共有パッケージが提供する登録関数を呼び出すだけの薄いファイルにできるためです。
共有パッケージの配布には、社内npmレジストリへの公開のほか、テンプレート専用リポジトリを用意してcopyオプションのGitHub URL指定で取り込む方法もあります。どちらの場合も、共有側の変更が全リポジトリへ波及する影響範囲の大きさを踏まえ、バージョンを明示的に固定し、更新は各リポジトリ側の判断で取り込む運用が安全です。変更履歴の整備とサンプル生成結果の添付を共有側のルールにすると、利用側の更新判断が容易になるでしょう。共有の仕組みは小さく始め、効果を確認しながら対象を広げるのが堅実です。
CIでの生成物検証を組み合わせたテンプレート陳腐化の防止ルール
ジェネレーター運用の最大の敵は、テンプレートの陳腐化です。リポジトリ本体の規約やライブラリ構成が進化する一方でテンプレートが放置されると、生成した瞬間にlintエラーになるコードが出来上がり、開発者は次第にジェネレーターを避けるようになります。この悪循環を断つには、テンプレートの鮮度を機械的に監視する仕組みが欠かせません。
有効な防止ルールは次のとおりです。
- CIでサンプル入力によるジェネレーター実行を行い、生成物がlint・型チェック・テストを通過することを毎回検証する
- 依存ライブラリやコード規約を変更するプルリクエストには、関連テンプレートの更新を含めることをレビュー条件とする
- 四半期に一度、全ジェネレーターの実行結果と現行の手書きコードを突き合わせ、乖離を棚卸しする
とくにCIでの自動検証は、陳腐化を「気づいた人が直す」属人運用から「壊れたら即検知される」仕組みへ転換する要です。検証ジョブの追加コストは生成対象の規模によって変わりますが、導入の負担に対して得られる安心感は大きいでしょう。
レビュー観点を統一しPR差分を最小化する生成コード運用の判断基準
ジェネレーター経由のコードが増えると、プルリクエストのレビュー方針にも調整が必要になります。生成直後の定型部分まで毎回精読するのは非効率であり、レビューの観点を「テンプレート由来の部分」と「開発者が書いた部分」に分離する運用が合理的です。テンプレート由来の構造はジェネレーター定義のレビュー時に一度だけ厳密に確認し、個別PRでは差分のうち手書き部分と入力値の妥当性に集中します。
PR差分を最小化する判断基準としては、生成とロジック実装を別コミットに分ける、可能ならば生成のみのPRを先行させるという2段構えが有効です。生成コミットが独立していれば、レビュアーは機械生成部分を一括で流し読みでき、本質的な変更だけに注意を向けられます。また、テンプレート変更時には影響を受ける既存コードの再生成方針(追従させるか、新規分からの適用とするか)を明文化しておくと、チーム内の判断のぶれを防げます。レビュー方針の合意は、ジェネレーター導入と同時に済ませておくのが理想でしょう。