nx-workspace-patterns について
nx-workspace-patternsは、Nxモノレポを構築、保守、移行する開発者向けのスキルです。ワークスペース構成、プロジェクト境界、依存関係、CIのaffected処理、リモートキャッシュを扱い、導入済みNxのバージョンに合わせた検証を促します。
主な機能
- 01Nxワークスペース構成とライブラリパターン
- 02プロジェクト境界と依存関係の指針
- 03CIワークフロー向けaffectedコマンド
- 04リモートキャッシュ設定の指針
- 05移行とジェネレーターの実践
活用シーン
- 01新しいNxワークスペースの作成
- 02プロジェクト間の境界設定
- 03affectedテストによるCI作業の削減
- 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-access | API 呼び出し、状態管理 | 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 を省略しない - 変更されたものだけをテストします
- 境界を無視しない - 技術的負債が蓄積します
- 細分化しすぎない - ライブラリ数とのバランスを取ります
リソース
制限事項
- タスクが上記の範囲に明確に該当する場合にのみ、このスキルを使用してください。
- 出力を、環境固有の検証、テスト、または専門家によるレビューの代わりとして扱わないでください。
- 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認してください。
コメント
Markdown 対応