Skip to content

ワークスペース

Voltaは、npm、Yarn、pnpmのワークスペース機能をサポートしており、モノレポ環境での開発を効率化します。このガイドでは、Voltaでワークスペースを効果的に管理する方法について説明します。

ワークスペースとは

ワークスペースは、複数の関連パッケージを単一のリポジトリで管理する方法です。これにより以下の利点があります:

  • 共通の依存関係の重複を削減
  • パッケージ間の依存関係管理の簡素化
  • 一元的なビルドとテストプロセス
  • 一貫したツールバージョンの使用

ワークスペースの設定

npmワークスペース

json
// ルートのpackage.json
{
  "name": "my-monorepo",
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "volta": {
    "node": "18.17.0",
    "npm": "9.8.0"
  }
}

Yarnワークスペース

json
// ルートのpackage.json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "volta": {
    "node": "18.17.0",
    "yarn": "1.22.19"
  }
}

pnpmワークスペース

yaml
# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
  - '!**/test/**'
json
// ルートのpackage.json
{
  "name": "my-monorepo",
  "volta": {
    "node": "18.17.0",
    "pnpm": "7.33.6"
  }
}

Voltaでのワークスペース管理

ツールバージョンの統一

Voltaは、ワークスペース全体で一貫したツールバージョンを保証します:

bash
# ルートディレクトリでツールを固定
volta pin node@18.17.0 npm@9.8.0

# すべてのワークスペースパッケージが同じバージョンを使用
cd packages/ui
npm --version  # 9.8.0

cd ../api
npm --version  # 9.8.0

個別パッケージの設定

個別のワークスペースパッケージで異なるツールが必要な場合:

json
// packages/legacy-app/package.json
{
  "name": "legacy-app",
  "volta": {
    "node": "14.21.3",
    "npm": "6.14.18"
  }
}

Voltaは、そのディレクトリで作業する際に自動的に適切なバージョンに切り替えます。

実践的なワークスペース例

フロントエンドモノレポ

my-frontend-monorepo/
├── package.json (Volta設定)
├── packages/
│   ├── ui-components/
│   │   └── package.json
│   ├── shared-utils/
│   │   └── package.json
│   └── theme/
│       └── package.json
└── apps/
    ├── web-app/
    │   └── package.json
    └── mobile-app/
        └── package.json
json
// ルートのpackage.json
{
  "name": "frontend-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "volta": {
    "node": "18.17.0",
    "npm": "9.8.0"
  },
  "scripts": {
    "build": "npm run build --workspaces",
    "test": "npm run test --workspaces",
    "dev": "npm run dev --workspaces"
  }
}

フルスタックモノレポ

fullstack-app/
├── package.json
├── frontend/
│   ├── package.json (React 18)
│   └── src/
├── backend/
│   ├── package.json (Node.js API)
│   └── src/
├── shared/
│   ├── package.json (共通ユーティリティ)
│   └── src/
└── mobile/
    ├── package.json (React Native)
    └── src/

一般的なワークフロー

依存関係の管理

bash
# ルートレベルで全体をインストール
npm install

# 特定のワークスペースに依存関係を追加
npm install lodash --workspace=packages/shared-utils

# ワークスペース間の依存関係を追加
npm install @myorg/shared-utils --workspace=apps/web-app

スクリプトの実行

bash
# すべてのワークスペースでスクリプトを実行
npm run build --workspaces

# 特定のワークスペースでスクリプトを実行
npm run test --workspace=packages/ui-components

# 並列実行(高速化)
npm run build --workspaces --parallel

選択的実行

bash
# 特定の条件でワークスペースを選択
npm run test --workspaces --if-present

# 依存関係がある場合のみ実行
npm run build --workspaces --include-dependencies

Yarn固有の機能

bash
# すべてのワークスペースで実行
yarn workspaces run build

# 特定のワークスペースで実行
yarn workspace web-app run dev

# ワークスペース情報を表示
yarn workspaces info

pnpm固有の機能

bash
# すべてのワークスペースで実行
pnpm run build --recursive

# フィルターで特定のワークスペースを選択
pnpm run test --filter "packages/*"

# 特定のワークスペースでコマンドを実行
pnpm --filter web-app run dev

CI/CDでのワークスペース

GitHub Actions

yaml
name: Monorepo CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        workspace: [packages/ui, packages/utils, apps/web]
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Install Volta
        run: |
          curl https://get.volta.sh | bash
          echo "$HOME/.volta/bin" >> $GITHUB_PATH
      
      - name: Install dependencies
        run: npm ci
      
      - name: Test workspace
        run: npm run test --workspace=${{ matrix.workspace }}

変更検出の最適化

yaml
- name: Get changed files
  id: changed-files
  uses: tj-actions/changed-files@v35
  with:
    files: |
      packages/**
      apps/**

- name: Test changed workspaces
  if: steps.changed-files.outputs.any_changed == 'true'
  run: |
    for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
      workspace=$(echo $file | cut -d'/' -f1-2)
      npm run test --workspace=$workspace
    done

ベストプラクティス

1. 一貫したツールバージョン

json
// ルートで統一されたツールバージョンを定義
{
  "volta": {
    "node": "18.17.0",
    "npm": "9.8.0"
  }
}

2. 依存関係の管理戦略

json
// ルートpackage.jsonでdevDependenciesを管理
{
  "devDependencies": {
    "typescript": "^5.0.0",
    "eslint": "^8.0.0",
    "prettier": "^3.0.0"
  }
}

3. 効率的なスクリプト設定

json
{
  "scripts": {
    "build": "npm run build --workspaces --if-present",
    "test": "npm run test --workspaces --if-present",
    "lint": "eslint packages/**/*.ts apps/**/*.ts",
    "clean": "npm run clean --workspaces --if-present"
  }
}

トラブルシューティング

依存関係の競合

bash
# 依存関係ツリーを確認
npm ls --all

# 重複した依存関係を確認
npm ls --depth=0

# ロックファイルを再生成
rm package-lock.json
npm install

ワークスペースの認識問題

bash
# ワークスペースの設定を確認
npm query ":attr(workspaces)"

# キャッシュをクリア
npm cache clean --force

# node_modulesを再インストール
rm -rf node_modules package-lock.json
npm install

パフォーマンスの最適化

bash
# .npmrcで設定
echo "prefer-workspace-packages=true" >> .npmrc
echo "save-workspace-protocol=false" >> .npmrc

# パッケージマネージャー固有の最適化
# pnpmの場合
echo "shared-workspace-lockfile=true" >> .npmrc