mono-repo-typescript について
pnpm workspacesで管理するTypeScriptモノレポの設計を支援するスキルです。サービス、アプリ、ライブラリを含む構成向けに、パッケージ分割、共有設定、ビルド編成、Docker Composeによる開発環境を扱います。
主な機能
- 01用途別のパッケージ構成
- 02pnpmワークスペースとカタログの設定
- 03TypeScriptプロジェクト参照とエイリアス
- 04ビルド順序とパッケージ依存関係の整理
- 05Docker Compose開発環境の構成
活用シーン
- 01複数パッケージのTypeScriptプロジェクト開始
- 02共有ライブラリとサービスの構成
- 03パッケージ設定とビルドの標準化
- 04ローカルの複数サービス環境の構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ beecode-rs/ claude-skills --skill mono-repo-typescriptインストール後、Claude Code で/mono-repo-typescriptを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSE.txtreferences/backend-packages.mdfrontend-packages.mdinfrastructure.mdscripts/build-esm-fix.jsclean.js詳細
TypeScript モノレポアーキテクチャ
目的
マイクロサービス、Web アプリ、モバイルアプリ、共有ライブラリなど、複数のパッケージを含む TypeScript モノレポの構成とオーケストレーションをガイドします。高レベルのアーキテクチャ、ビルドオーケストレーション、開発環境に焦点を当てます。
対象範囲:
- このスキル: モノレポの構成、パッケージの整理、Docker Compose、ビルドオーケストレーション
- writing-clean-ts スキル: 個々のパッケージのコードパターン(サービス、リポジトリ、コントローラー)
- test-typescript スキル: テストパターンとカバレッジ
使用する場面
- pnpm ワークスペースで新しいモノレポをセットアップするとき
- パッケージフォルダー(マイクロサービス、Web、モバイル、ライブラリ)を構成するとき
- 共有ライブラリ(common、node-common、react-common)を設定するとき
- パスエイリアスを使って ES モジュールをセットアップするとき
- 設定(TypeScript、ESLint、Vitest)を一元管理するとき
- 開発用に Docker Compose をオーケストレーションするとき
- パッケージ間の依存関係を管理するとき
- 複数のパッケージに拡張する可能性がある TypeScript プロジェクトを新しく始めるとき
使用しない場面
- 単一パッケージのプロジェクト → 代わりに
writing-clean-tsスキルを使用します - Yarn または npm のワークスペース → このスキルは pnpm 専用です
- TypeScript 以外のモノレポ → ここで紹介するパターンは、全体で TypeScript を使用することを前提としています
- 異なる規約を採用している既存のモノレポ → 必要に応じてパターンを調整してください
簡単な判断ガイド
適切なパッケージタイプの選択:
| 必要なもの... | 作成するもの... | 依存関係 |
|---|---|---|
| 共有ビジネスモデル、ユーティリティ | packages/common/ | なし(純粋) |
| データベース、ロギング、メッセージング(Node.js) | packages/node-common/ | common |
| 共有 React コンポーネント、フック | packages/react-common/ | common |
| バックエンド API/マイクロサービス | packages/node-{domain}/ | common、node-common |
| Web アプリケーション(Vite) | packages/react-{name}/ | common、react-common |
| モバイルアプリ(Expo) | packages/mobile-app/ | common、react-common |
| マーケティング/一般公開サイト | packages/website/ | common、react-common |
依存関係の流れ:
common → node-common → node-{service}
common → react-common → react-{app} / mobile-app
モノレポ構成の概要
project-root/
├── packages/ # All packages live here
│ ├── common/ # Shared business models, utilities
│ ├── node-common/ # Node.js-specific utilities
│ ├── react-common/ # React shared components
│ ├── config/ # Shared ESLint, Prettier, TypeScript configs
│ ├── node-core/ # Backend microservice
│ ├── node-auth/ # Auth microservice
│ ├── react-admin/ # Admin web app
│ ├── react-core/ # Main web app
│ ├── mobile-app/ # Mobile app (React Native/Expo)
│ └── website/ # Marketing site (Next.js)
├── config/ # Root-level shared configs
│ ├── typescript/ # TypeScript base configs
│ ├── vitest/ # Vitest base configs
│ └── eslint/ # ESLint base configs
├── resource/
│ ├── script/ # Build and utility scripts
│ ├── docker/ # Dockerfiles
│ └── secret/ # Encrypted secrets
├── package.json # Root orchestration
├── pnpm-workspace.yaml # Workspace and catalog config
├── tsconfig.json # TypeScript project references
├── compose.yml # Docker Compose for development
└── .env.example # Environment template
ルートのオーケストレーション
package.json
{
"name": "project-name",
"type": "module",
"private": true,
"engines": {
"node": ">=22 <23",
"pnpm": ">=10 <11"
},
"scripts": {
"build": "tsc -b && pnpm -r build",
"clean": "pnpm -r clean",
"lint": "prettier . && eslint . && pnpm -r lint",
"test": "pnpm -r test",
"watch": "tsc -b -w",
"ws-build": "pnpm --filter",
"ws-test": "pnpm --filter"
},
"devDependencies": {
"@types/node": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:",
"eslint": "catalog:",
"prettier": "catalog:"
},
"pnpm": {
"overrides": {
"@internal/msh-*": "link:../external-msh-monorepo/packages/$1"
}
}
}
注:
pnpm.overridesセクションでは、外部モノレポのパッケージをリンクする方法を示しています。特定のプロジェクト設定向けの例です。不要な場合は削除してください。
pnpm-workspace.yaml
packages:
- packages/*
catalog:
typescript: ^5.7
vitest: ^3.0
eslint: ^9.22
prettier: ^3.5
"@types/node": ^22
zod: ^3.24
express: ^5.0
react: ^19
"@mui/material": ^7
catalogProtocols:
# Example for external monorepo linking:
# msh-internal: link:
注: これらのバージョンを参照するには、package.json で
catalog:を使用してください。これにより、すべてのパッケージで一貫性が保たれます。
tsconfig.json(プロジェクト参照)
{
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "packages/common" },
{ "path": "packages/node-common" },
{ "path": "packages/react-common" },
{ "path": "packages/node-core" },
{ "path": "packages/react-admin" }
],
"files": []
}
パッケージタイプの概要
| パッケージ | 目的 | 依存関係 |
|---|---|---|
common | 共有ビジネスモデル、ユーティリティ | なし(純粋) |
node-common | Node.js インフラストラクチャ(DB、ロギング、MQ) | common |
react-common | 共有 React コンポーネント、フック | common |
node-* | バックエンドマイクロサービス | common、node-common |
react-* | フロントエンド Web アプリ | common、react-common |
mobile-app | React Native/Expo アプリ | common、react-common |
パッケージ設定の詳細については、以下を参照してください:
- バックエンドパッケージ - common、node-common、マイクロサービス
- フロントエンドパッケージ - react-common、Web アプリ、モバイル
ES モジュールとパスエイリアス
#src/* パターン
各パッケージでは、インポートをすっきりさせるためにパスエイリアスを使用します。
tsconfig.json:
{
"compilerOptions": {
"paths": {
"#src": ["./src"],
"#src/*": ["./src/*"]
}
}
}
package.json:
{
"imports": {
"#src/*": "./dist/*.js"
}
}
コード内での使用例:
import { someUtil } from '#src/util/some-util.js'
import { UserModel } from '#src/business/model/user/user-model.js'
重要な理由: #src/* エイリアスは、コンパイル時(TypeScript のパス)と実行時(Node.js のサブパスインポート)の両方で機能するため、パスを書き換えなくてもビルド済みコードが動作します。
ビルドプロセス
# 1. Clean dist
node ../../resource/script/npm/clean.js .
# 2. Compile TypeScript
tsc -p ./tsconfig.build.json
# 3. Resolve aliases (tsc-alias)
tsc-alias -p ./tsconfig.build.json
パッケージ間の依存関係
依存関係の階層
@app/common (core models, utilities)
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
node-common node-core react-common
│ │ │
│ │ │
└───────────────┴───────────────┘
│
▼
Frontend Apps
(react-admin, react-core, mobile-app)
ワークスペース依存関係
package.json 内:
{
"dependencies": {
"@app/common": "workspace:*",
"@app/node-common": "workspace:*",
"@app/react-common": "workspace:*",
"@app/config": "workspace:*"
}
}
カタログ依存関係
package.json 内:
{
"dependencies": {
"zod": "catalog:",
"express": "catalog:",
"typeorm": "catalog:"
},
"devDependencies": {
"typescript": "catalog:",
"vitest": "catalog:"
}
}
Docker Compose による開発
Docker のセットアップ全体については、インフラストラクチャリファレンスを参照してください
クイックスタート
# compose.yml - minimal example
services:
node-core:
build:
context: .
dockerfile: resource/docker/Dockerfile.node-base
command: pnpm run serve
working_dir: /app/packages/node-core
volumes:
- ./:/app:ro
depends_on:
pg: { condition: service_healthy }
labels:
- "traefik.http.routers.node-core.rule=PathPrefix(`/api/core`)"
よく使うコマンド
docker compose up -d # Start all services
docker compose logs -f node-core # View logs
docker compose up -d --build node-core # Rebuild
docker compose down # Stop all
プロセス
1. 要件を分析する
- 必要なパッケージの種類(サービス、アプリ、ライブラリ)を特定する
- 共有コードの境界を決定する
- 依存関係の階層を計画する
2. パッケージを構成する
./packages/フォルダーにパッケージを作成する- 共通ライブラリ(common、node-common、react-common)を先に設定する
- 適切な exports とワークスペース依存関係を指定して package.json を設定する
- ベース設定を拡張する tsconfig.json を作成する
3. ルートを設定する
- カタログを含む pnpm-workspace.yaml を設定する
- ルートの package.json スクリプトを設定する
- プロジェクト参照を含む tsconfig.json を作成する
- config/ に一元化された設定を用意する
4. Docker を設定する
- すべてのサービスを含む compose.yml を作成する
- Traefik のルーティングを設定する
- ヘルスチェックを設定する
- 開発用のボリュームマウントを設定する
5. セットアップを確認する
pnpm install # Install dependencies
pnpm build # Build all packages
pnpm test # Run tests
docker compose up -d # Start development environment
新しいパッケージの追加
新しいパッケージを作成する際は、このチェックリストを使用してください。
バックエンドパッケージ
- ディレクトリを作成する:
packages/node-{name}/ - 次の内容で
package.jsonを作成する:name:@app/node-{name}type:module#src/*用のexportsとimports- 依存関係:
@app/common、@app/node-commonをworkspace:*として指定 - ビルドスクリプト
-
../../config/typescript/tsconfig.base.jsonを拡張するtsconfig.jsonを作成する - 本番ビルド用の
tsconfig.build.jsonを作成する - エントリーポイントとして
app/server-app.tsを含むsrc/を作成する - ルートの
tsconfig.jsonの参照に追加する - Traefik ラベルを付けて
compose.ymlに追加する -
pnpm installを実行する
フロントエンドパッケージ
- ディレクトリを作成する:
packages/react-{name}/ - 次の内容で
package.jsonを作成する:name:@app/react-{name}type:module- 依存関係:
@app/common、@app/react-commonをworkspace:*として指定 - 開発サーバー用の Vite 設定
-
../../config/typescript/tsconfig.react.base.jsonを拡張するtsconfig.jsonを作成する -
vite-tsconfig-pathsプラグインを含むvite.config.tsを作成する - エントリーポイントとして
main.tsxを含むsrc/を作成する - ルートの
tsconfig.jsonの参照に追加する - 必要に応じて
compose.ymlに追加する -
pnpm installを実行する
ベストプラクティス
パッケージの命名
- 内部パッケージには
@app/プレフィックスを使用する - バックエンド:
node-{domain}(例:node-core、node-auth) - フロントエンド:
react-{purpose}(例:react-admin、react-core) - 共有:
common、node-common、react-common
バージョン管理
- 共有依存関係のバージョンには
catalog:を使用する - 内部パッケージには
workspace:*を使用する - パッケージ間でバージョンを統一する
ビルド順序
- まず共通ライブラリをビルドする
- 次にプラットフォーム固有のライブラリをビルドする
- 最後にアプリ/サービスをビルドする
- 正しい順序でビルドするため、TypeScript のプロジェクト参照を使用する
開発ワークフロー
- スタック全体の開発には Docker Compose を使用する
- ホットリロードにはボリュームマウントを使用する
- サービス間のルーティングには Traefik を使用する
- サービスの依存関係にはヘルスチェックを使用する
よくある問題
- 循環依存: common がプラットフォーム固有のライブラリに依存しないようにしてください
- モジュールシステムの混在: すべてのパッケージで ES モジュール(
"type": "module")を使用してください - exports の不足: package.json の
exportsフィールドを必ず定義してください - パスの誤り: tsconfig のパスが package.json の imports と一致していることを確認してください
- カタログの不整合: pnpm-workspace.yaml のカタログバージョンを一貫させてください
- .js 拡張子の不足: ES モジュールでは import パスに
.jsが必要です
トラブルシューティング
ERR_PNPM_NO_MATCHING_VERSION
原因: パッケージが、pnpm-workspace.yaml に存在しない catalog: 依存関係を参照しています
対処方法: 不足しているパッケージをカタログに追加するか、明示的なバージョンを使用してください:
# pnpm-workspace.yaml
catalog:
your-missing-package: ^1.0.0
TypeScript のプロジェクト参照エラー
原因: ルートの tsconfig.json でパッケージが参照されていますが、存在しないか、エラーがあります
対処方法:
- パッケージが
packages/フォルダーに存在することを確認する pnpm installを実行してワークスペースパッケージをリンクする- 先に依存関係をビルドする:
pnpm --filter @app/common build
Cannot find module '#src/...'
原因: パスエイリアスの設定が正しくないか、パッケージがビルドされていません。
修正方法:
tsconfig.jsonでpathsが設定されていることを確認しますpackage.jsonでimportsが設定されていることを確認します- パッケージ内で
pnpm buildを実行します - インポートで
.js拡張子を使用していることを確認します
ビルド済みコードでの ES モジュールエラー
原因: TypeScript が .js 拡張子なしでインポートを出力しています。
修正方法: ビルド後に tsc-alias を実行するか、同梱の修正スクリプトを使用します:
node scripts/build-esm-fix.js packages/your-package
Docker ボリュームの権限エラー
原因: コンテナがホストとは異なるユーザーで実行されています。
修正方法:
- インストール後に Dockerfile へ
USER nodeを追加します - または、次を実行します:
docker compose exec node-core chown -R node:node /app
「Cannot find module」エラーでテストが失敗する
原因: Vitest の設定でパスエイリアスが解決されていません。
修正方法: vitest の設定で vite-tsconfig-paths を使用します:
import tsconfigPaths from 'vite-tsconfig-paths'
export default {
test: { ... },
plugins: [tsconfigPaths()]
}
ワークスペースパッケージが見つからない
原因: workspace:* 依存関係がインストールされていません。
修正方法:
- ルートで
pnpm installを実行します package.jsonのパッケージ名が完全に一致していることを確認します- パッケージが
packages/フォルダー内にあることを確認します
同梱スクリプト
このスキルには、scripts/ 内にヘルパースクリプトが含まれています:
clean.js-dist/フォルダーを削除しますbuild-esm-fix.js- ES モジュールのインポートに.js拡張子を追加します
これらをプロジェクトの resource/script/npm/ にコピーし、package.json で参照します:
{
"scripts": {
"build": "node ../../resource/script/npm/clean.js . && tsc -p ./tsconfig.build.json && tsc-alias -p ./tsconfig.build.json"
}
}
参考資料
- バックエンドパッケージ - common、node-common、マイクロサービスの詳細な設定
- フロントエンドパッケージ - react-common、Web アプリ、モバイルの詳細な設定
- インフラストラクチャ - Docker Compose、ビルドスクリプト、集中管理された設定