mcpField
N
nx-workspace-patterns

nx-workspace-patterns

github.com/sickn33開発48.8k153 回インストール今日更新
リポジトリ

nx-workspace-patterns について

nx-workspace-patternsは、Nxモノレポを構築、保守、移行する開発者向けのスキルです。ワークスペース構成、プロジェクト境界、依存関係、CIのaffected処理、リモートキャッシュを扱い、導入済みNxのバージョンに合わせた検証を促します。

主な機能

  1. 01Nxワークスペース構成とライブラリパターン
  2. 02プロジェクト境界と依存関係の指針
  3. 03CIワークフロー向けaffectedコマンド
  4. 04リモートキャッシュ設定の指針
  5. 05移行とジェネレーターの実践

活用シーン

  1. 01新しいNxワークスペースの作成
  2. 02プロジェクト間の境界設定
  3. 03affectedテストによるCI作業の削減
  4. 04Nx移行の計画

インストール

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

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill nx-workspace-patterns

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

詳細

Nx ワークスペースのパターン

Nx モノレポ管理の本番環境向けパターンです。

このスキルを使用しない場合

  • タスクが Nx ワークスペースのパターンに関係しない場合
  • この範囲外の別の分野やツールが必要な場合

手順

  • 目標、制約、必要な入力を明確にします。
  • 関連するベストプラクティスを適用し、結果を検証します。
  • 実行可能な手順と検証方法を提示します。

このスキルを使用する場合

  • 新しい Nx ワークスペースを設定する場合
  • プロジェクトの境界を構成する場合
  • affected コマンドで CI を最適化する場合
  • リモートキャッシュを導入する場合
  • プロジェクト間の依存関係を管理する場合
  • Nx に移行する場合

基本概念

1. Nx アーキテクチャ
workspace/
├── apps/              # Deployable applications
│   ├── web/
│   └── api/
├── libs/              # Shared libraries
│   ├── shared/
│   │   ├── ui/
│   │   └── utils/
│   └── feature/
│       ├── auth/
│       └── dashboard/
├── tools/             # Custom executors/generators
├── nx.json            # Nx configuration
└── workspace.json     # Project configuration
2. ライブラリの種類
種類目的例
featureスマートコンポーネント、ビジネスロジックfeature-auth
ui表示用コンポーネントui-buttons
data-accessAPI 呼び出し、状態管理data-access-users
util純粋関数、ヘルパーutil-formatting
shellアプリの起動処理shell-web

テンプレート

以下の例には、旧式と最新の Nx 設定が混在しています。ワークスペースの Nx/プラグインのバージョンを固定し、インストール済みのスキーマに照らして検証してください。npmScope/tasksRunnerOptions やジェネレーターのオプションを、バージョンを確認せずに流用しないでください。Nx Cloud トークンは環境変数やシークレットストレージで管理し、accessToken フィールドに値を直接記述してコミットしないでください。完全な入力/出力宣言を備えた、決定的なタスクのみをキャッシュしてください。変更される可能性のあるサービスに対する E2E テストでは、キャッシュを無効にして実行する必要がある場合があります。affected の選択は、依存関係グラフが完全で、base/head が正しいことを前提とします。ポリシー、共有部分、または不明な変更については、必須の全テストスイートを引き続き実行してください。移行コマンドはマニフェストやコードを変更するため、クリーンで復旧可能なトピックブランチで実行し、レビューしてください。

テンプレート 1:nx.json の設定
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "npmScope": "myorg",
  "affected": {
    "defaultBase": "main"
  },
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default",
      "options": {
        "cacheableOperations": [
          "build",
          "lint",
          "test",
          "e2e",
          "build-storybook"
        ],
        "parallel": 3
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"],
      "cache": true
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
      "cache": true
    },
    "lint": {
      "inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
      "cache": true
    },
    "e2e": {
      "inputs": ["default", "^production"],
      "cache": true
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.[jt]s",
      "!{projectRoot}/.eslintrc.json"
    ],
    "sharedGlobals": [
      "{workspaceRoot}/babel.config.json",
      "{workspaceRoot}/tsconfig.base.json"
    ]
  },
  "generators": {
    "@nx/react": {
      "application": {
        "style": "css",
        "linter": "eslint",
        "bundler": "webpack"
      },
      "library": {
        "style": "css",
        "linter": "eslint"
      },
      "component": {
        "style": "css"
      }
    }
  }
}
テンプレート 2:プロジェクトの設定
// apps/web/project.json
{
  "name": "web",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/web/src",
  "projectType": "application",
  "tags": ["type:app", "scope:web"],
  "targets": {
    "build": {
      "executor": "@nx/webpack:webpack",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "compiler": "babel",
        "outputPath": "dist/apps/web",
        "index": "apps/web/src/index.html",
        "main": "apps/web/src/main.tsx",
        "tsConfig": "apps/web/tsconfig.app.json",
        "assets": ["apps/web/src/assets"],
        "styles": ["apps/web/src/styles.css"]
      },
      "configurations": {
        "development": {
          "extractLicenses": false,
          "optimization": false,
          "sourceMap": true
        },
        "production": {
          "optimization": true,
          "outputHashing": "all",
          "sourceMap": false,
          "extractLicenses": true
        }
      }
    },
    "serve": {
      "executor": "@nx/webpack:dev-server",
      "defaultConfiguration": "development",
      "options": {
        "buildTarget": "web:build"
      },
      "configurations": {
        "development": {
          "buildTarget": "web:build:development"
        },
        "production": {
          "buildTarget": "web:build:production"
        }
      }
    },
    "test": {
      "executor": "@nx/jest:jest",
      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
      "options": {
        "jestConfig": "apps/web/jest.config.ts",
        "passWithNoTests": true
      }
    },
    "lint": {
      "executor": "@nx/eslint:lint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/web/**/*.{ts,tsx,js,jsx}"]
      }
    }
  }
}
テンプレート 3:モジュール境界ルール
// .eslintrc.json
{
  "root": true,
  "ignorePatterns": ["**/*"],
  "plugins": ["@nx"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {
        "@nx/enforce-module-boundaries": [
          "error",
          {
            "enforceBuildableLibDependency": true,
            "allow": [],
            "depConstraints": [
              {
                "sourceTag": "type:app",
                "onlyDependOnLibsWithTags": [
                  "type:feature",
                  "type:ui",
                  "type:data-access",
                  "type:util"
                ]
              },
              {
                "sourceTag": "type:feature",
                "onlyDependOnLibsWithTags": [
                  "type:ui",
                  "type:data-access",
                  "type:util"
                ]
              },
              {
                "sourceTag": "type:ui",
                "onlyDependOnLibsWithTags": ["type:ui", "type:util"]
              },
              {
                "sourceTag": "type:data-access",
                "onlyDependOnLibsWithTags": ["type:data-access", "type:util"]
              },
              {
                "sourceTag": "type:util",
                "onlyDependOnLibsWithTags": ["type:util"]
              },
              {
                "sourceTag": "scope:web",
                "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"]
              },
              {
                "sourceTag": "scope:api",
                "onlyDependOnLibsWithTags": ["scope:api", "scope:shared"]
              },
              {
                "sourceTag": "scope:shared",
                "onlyDependOnLibsWithTags": ["scope:shared"]
              }
            ]
          }
        ]
      }
    }
  ]
}
テンプレート 4:カスタムジェネレーター
// tools/generators/feature-lib/index.ts
import {
  Tree,
  formatFiles,
  generateFiles,
  joinPathFragments,
  names,
  readProjectConfiguration,
} from '@nx/devkit';
import { libraryGenerator } from '@nx/react';

interface FeatureLibraryGeneratorSchema {
  name: string;
  scope: string;
  directory?: string;
}

export default async function featureLibraryGenerator(
  tree: Tree,
  options: FeatureLibraryGeneratorSchema
) {
  const { name, scope, directory } = options;
  const projectDirectory = directory
    ? `${directory}/${name}`
    : `libs/${scope}/feature-${name}`;

  // Generate base library
  await libraryGenerator(tree, {
    name: `feature-${name}`,
    directory: projectDirectory,
    tags: `type:feature,scope:${scope}`,
    style: 'css',
    skipTsConfig: false,
    skipFormat: true,
    unitTestRunner: 'jest',
    linter: 'eslint',
  });

  // Add custom files
  const projectConfig = readProjectConfiguration(tree, `${scope}-feature-${name}`);
  const projectNames = names(name);

  generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'),
    projectConfig.sourceRoot,
    {
      ...projectNames,
      scope,
      tmpl: '',
    }
  );

  await formatFiles(tree);
}
テンプレート 5:affected を使用した CI 設定
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Derive SHAs for affected commands
        uses: nrwl/nx-set-shas@v4

      - name: Run affected lint
        run: npx nx affected -t lint --parallel=3

      - name: Run affected test
        run: npx nx affected -t test --parallel=3 --configuration=ci

      - name: Run affected build
        run: npx nx affected -t build --parallel=3

      - name: Run affected e2e
        run: npx nx affected -t e2e --parallel=1
テンプレート 6:リモートキャッシュの設定
// nx.json with Nx Cloud
{
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx-cloud",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"],
        "accessToken": "your-nx-cloud-token",
        "parallel": 3,
        "cacheDirectory": ".nx/cache"
      }
    }
  },
  "nxCloudAccessToken": "your-nx-cloud-token"
}

// Self-hosted cache with S3
{
  "tasksRunnerOptions": {
    "default": {
      "runner": "@nx-aws-cache/nx-aws-cache",
      "options": {
        "cacheableOperations": ["build", "lint", "test"],
        "awsRegion": "us-east-1",
        "awsBucket": "my-nx-cache-bucket",
        "awsProfile": "default"
      }
    }
  }
}

よく使うコマンド

# Generate new library
nx g @nx/react:lib feature-auth --directory=libs/web --tags=type:feature,scope:web

# Run affected tests
nx affected -t test --base=main

# View dependency graph
nx graph

# Run specific project
nx build web --configuration=production

# Reset cache
nx reset

# Run migrations
nx migrate latest
nx migrate --run-migrations

ベストプラクティス

推奨事項
  • タグを一貫して使用する - モジュール境界で強制します
  • 早い段階でキャッシュを有効にする - CI の実行時間を大幅に短縮できます
  • ライブラリの責務を絞る - 単一責任を守ります
  • ジェネレーターを使用する - 一貫性を確保します
  • 境界を文書化する - 新しい開発者の助けになります
非推奨事項
  • 循環依存を作らない - グラフは非巡回にします
  • affected を省略しない - 変更されたものだけをテストします
  • 境界を無視しない - 技術的負債が蓄積します
  • 細分化しすぎない - ライブラリ数とのバランスを取ります

リソース

制限事項

  • タスクが上記の範囲に明確に該当する場合にのみ、このスキルを使用してください。
  • 出力を、環境固有の検証、テスト、または専門家によるレビューの代わりとして扱わないでください。
  • 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認してください。

コメント