mcpField
M
mono-repo-typescript

mono-repo-typescript

github.com/beecode-rs開発047 回インストール2 週間前に更新
リポジトリ

mono-repo-typescript について

pnpm workspacesで管理するTypeScriptモノレポの設計を支援するスキルです。サービス、アプリ、ライブラリを含む構成向けに、パッケージ分割、共有設定、ビルド編成、Docker Composeによる開発環境を扱います。

主な機能

  1. 01用途別のパッケージ構成
  2. 02pnpmワークスペースとカタログの設定
  3. 03TypeScriptプロジェクト参照とエイリアス
  4. 04ビルド順序とパッケージ依存関係の整理
  5. 05Docker Compose開発環境の構成

活用シーン

  1. 01複数パッケージのTypeScriptプロジェクト開始
  2. 02共有ライブラリとサービスの構成
  3. 03パッケージ設定とビルドの標準化
  4. 04ローカルの複数サービス環境の構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/beecode-rs/claude-skills --skill mono-repo-typescript

インストール後、Claude Code で/mono-repo-typescriptを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE.txt
references/
backend-packages.md
frontend-packages.md
infrastructure.md
scripts/
build-esm-fix.js
clean.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-commonNode.js インフラストラクチャ(DB、ロギング、MQ)common
react-common共有 React コンポーネント、フックcommon
node-*バックエンドマイクロサービスcommon、node-common
react-*フロントエンド Web アプリcommon、react-common
mobile-appReact Native/Expo アプリcommon、react-common

パッケージ設定の詳細については、以下を参照してください:

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

新しいパッケージの追加

新しいパッケージを作成する際は、このチェックリストを使用してください。

バックエンドパッケージ
  1. ディレクトリを作成する:packages/node-{name}/
  2. 次の内容で package.json を作成する:
    • name:@app/node-{name}
    • type:module
    • #src/* 用の exports と imports
    • 依存関係:@app/common、@app/node-common を workspace:* として指定
    • ビルドスクリプト
  3. ../../config/typescript/tsconfig.base.json を拡張する tsconfig.json を作成する
  4. 本番ビルド用の tsconfig.build.json を作成する
  5. エントリーポイントとして app/server-app.ts を含む src/ を作成する
  6. ルートの tsconfig.json の参照に追加する
  7. Traefik ラベルを付けて compose.yml に追加する
  8. pnpm install を実行する
フロントエンドパッケージ
  1. ディレクトリを作成する:packages/react-{name}/
  2. 次の内容で package.json を作成する:
    • name:@app/react-{name}
    • type:module
    • 依存関係:@app/common、@app/react-common を workspace:* として指定
    • 開発サーバー用の Vite 設定
  3. ../../config/typescript/tsconfig.react.base.json を拡張する tsconfig.json を作成する
  4. vite-tsconfig-paths プラグインを含む vite.config.ts を作成する
  5. エントリーポイントとして main.tsx を含む src/ を作成する
  6. ルートの tsconfig.json の参照に追加する
  7. 必要に応じて compose.yml に追加する
  8. pnpm install を実行する

ベストプラクティス

パッケージの命名
  • 内部パッケージには @app/ プレフィックスを使用する
  • バックエンド:node-{domain}(例:node-core、node-auth)
  • フロントエンド:react-{purpose}(例:react-admin、react-core)
  • 共有:common、node-common、react-common
バージョン管理
  • 共有依存関係のバージョンには catalog: を使用する
  • 内部パッケージには workspace:* を使用する
  • パッケージ間でバージョンを統一する
ビルド順序
  1. まず共通ライブラリをビルドする
  2. 次にプラットフォーム固有のライブラリをビルドする
  3. 最後にアプリ/サービスをビルドする
  4. 正しい順序でビルドするため、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 でパッケージが参照されていますが、存在しないか、エラーがあります

対処方法:

  1. パッケージが packages/ フォルダーに存在することを確認する
  2. pnpm install を実行してワークスペースパッケージをリンクする
  3. 先に依存関係をビルドする:pnpm --filter @app/common build
Cannot find module '#src/...'

原因: パスエイリアスの設定が正しくないか、パッケージがビルドされていません。

修正方法:

  1. tsconfig.json で paths が設定されていることを確認します
  2. package.json で imports が設定されていることを確認します
  3. パッケージ内で pnpm build を実行します
  4. インポートで .js 拡張子を使用していることを確認します
ビルド済みコードでの ES モジュールエラー

原因: TypeScript が .js 拡張子なしでインポートを出力しています。

修正方法: ビルド後に tsc-alias を実行するか、同梱の修正スクリプトを使用します:

node scripts/build-esm-fix.js packages/your-package
Docker ボリュームの権限エラー

原因: コンテナがホストとは異なるユーザーで実行されています。

修正方法:

  1. インストール後に Dockerfile へ USER node を追加します
  2. または、次を実行します: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:* 依存関係がインストールされていません。

修正方法:

  1. ルートで pnpm install を実行します
  2. package.json のパッケージ名が完全に一致していることを確認します
  3. パッケージが 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"
  }
}

参考資料

外部リソース

コメント