【実務・中級編】 Project References (composite) – TypeScript実践ガイド

モノレポの闇を光に変える:TypeScript Project Referencesを極める

やあ。今日もフロントエンドの戦場でコードと格闘している君へ。

大規模なプロジェクトになると、`tsc`を叩くたびにPCが唸りを上げ、ビルド完了までの待ち時間にコーヒーを淹れに行く……そんな経験はないかな?あるいは、一つの巨大な`tsconfig.json`を複数人で編集して、コンフリクトの嵐に巻き込まれたことは?

TypeScriptの「Project References (`composite: true`)」は、そんな泥沼から僕らを救い出してくれる、いわば「大規模開発の救世主」だ。今日は、この機能をただの教科書的な説明ではなく、現場のリアルな視点から深掘りしてみよう。

—

なぜ今、Project Referencesが必要なのか?

結論から言うと、「分割」と「キャッシュ」のためだ。

通常、`tsc`はプロジェクト全体を一度に解析し、型情報をメモリに乗せようとする。プロジェクトが数万行を超えたあたりで、このアプローチは限界を迎える。コンパイル時間は指数関数的に増え、エディタの補完も重くなる。

Project Referencesを使うと、TypeScriptはプロジェクトを「独立したビルド単位」として認識する。一度ビルドされたサブプロジェクトは`.d.ts`と`.tsbuildinfo`(ビルドの証跡)としてキャッシュされ、変更がない限り再計算されない。

ブラウザがどう処理しているか? という問いに対しては、少し補足が必要だ。TypeScriptはコンパイル後にJavaScriptを出力するが、ブラウザはTypeScriptそのものを動かしているわけではない。Project Referencesはあくまで「ビルドパイプラインの最適化」であり、「ブラウザに届くJavaScriptの品質や整合性を、いかに高速かつ安全に担保するか」という、僕らエンジニアのための戦術なんだ。

—

実践:Project Referencesの構成術

現場で最も汎用的な「コアロジック」と「UI層」に分ける構成を見てみよう。

1. ディレクトリ構造

my-app/
├── packages/
│ ├── core/ # 共通ビジネスロジック
│ │ ├── tsconfig.json
│ │ └── src/index.ts
│ └── web/ # フロントエンドUI
│ ├── tsconfig.json
│ └── src/index.ts
└── tsconfig.json # ルート(全体管理)

2. 設定ファイルの書き方(ここが肝だ)

まずは共通の`core`プロジェクト。`composite: true`が必須だ。

// packages/core/tsconfig.json
{
“compilerOptions”: {
“composite”: true, // これがProject Referencesの心臓部
“declaration”: true, // 型定義ファイルを生成する(必須)
“outDir”: “dist”,
“strict”: true
}
}

次に、それを利用する`web`プロジェクト。

// packages/web/tsconfig.json
{
“compilerOptions”: {
“composite”: true,
“outDir”: “dist”
},
“references”: [
{ “path”: “../core” } // ここで依存関係を明示する
]
}

最後に、ルートの`tsconfig.json`で全体を統括する。

// tsconfig.json (ルート)
{
“files”: [], // ルート自体はソースを持たないので空にする
“references”: [
{ “path”: “./packages/core” },
{ “path”: “./packages/web” }
]
}

—

現場で直面する「落とし穴」への対策

この機能を導入すると、最初は快適だが、いくつかハマりどころがある。シニアとしてのアドバイスを置いておくよ。

1. `declaration: true`を忘れるな:
`composite: true`にすると、TypeScriptは自動的に`declaration`を有効にしようとする。サブプロジェクト間で型を共有するには、型定義ファイル(`.d.ts`)が不可欠だからだ。これをサボるとビルドが通らない。

2. `outFile`との併用は不可能:
`outFile`オプションを使っている古いプロジェクトには適用できない。現代のモジュールベース(ESM)開発なら問題ないはずだ。

3. CI/CDでのビルドコマンド:
ルートディレクトリで単に `tsc` と打つだけでは不十分な場合がある。CI上では `tsc –build –verbose` を使うのが鉄則だ。`–verbose`をつけると、どのプロジェクトが再ビルドされたのかが手に取るようにわかる。

—

最後に:エンジニアとしてのマインドセット

Project Referencesは、ただの高速化ツールではない。「疎結合な設計を強制するツール」でもあるんだ。

サブプロジェクトを分けると、不用意な循環参照ができなくなる。`core`から`web`を参照しようとすると、TypeScriptが「依存関係のループだよ」と警告してくれる。これによって、コードの依存関係が自然と整理され、テストもしやすい、堅牢なアーキテクチャへと導かれる。

面倒な設定に見えるかもしれない。だが、この一手間が、半年後の君自身やチームメンバーを、スパゲッティコードの迷宮から救い出すことになる。

さあ、エディタを開いて、まずは小さなパッケージから分割を始めてみよう。何か詰まったら、いつでも聞いてくれ。応援しているよ。

コメント

タイトルとURLをコピーしました