跳到主要内容

Nx ワークスペースとモノレポ開発

Nxは、Angularを含む大規模アプリケーションのモノレポ管理に特化したビルドシステムです。Google、Microsoft、Cisco などの企業で採用されており、チーム間の境界管理、ビルドの高速化、コードの一貫性を実現します。

1. Nxとは何か

概要と哲学

Nxはスマートで高速なビルドシステムです。モノレポ内の複数プロジェクトを効率的に管理し、以下の課題を解決します。

  • ビルド時間の短縮: キャッシュと影響範囲分析により、変更箇所に関連するタスクだけを実行
  • コード共有の促進: ライブラリの作成・共有が容易で、コードの重複を防止
  • 依存関係の管理: プロジェクト間の依存関係を自動検出し、ビルド順序を最適化
  • 一貫性の確保: ジェネレータと境界ルールにより、チーム全体でコーディング規約を統一

Angular CLI との関係

NxはAngular CLIを拡張する形で動作します。ng コマンドの代わりに nx コマンドを使いますが、内部的にはAngular CLIの機能を利用しています。

# Angular CLI
ng serve my-app
ng build my-app

# Nx(同等のコマンド)
nx serve my-app
nx build my-app

Integrated Monorepo vs Package-Based Monorepo

方式説明適したケース
IntegratedNxが全プロジェクトを一元管理。ビルド・テスト・リンクを統一的に実行新規モノレポ、Angularプロジェクト
Package-Based各パッケージが独自の package.json を持つ。npm/yarn workspacesに近い既存プロジェクトの段階的移行

Turborepo との比較

機能NxTurborepo
キャッシュローカル + リモート(Nx Cloud)ローカル + リモート(Vercel)
コード生成ジェネレータ(強力)なし
プロジェクトグラフ対話的なビジュアルグラフ基本的なグラフ
モジュール境界ESLintルールで強制可能なし
主な対象Angular, React, Node.js 等主にNext.js / Reactエコシステム

2. Nx ワークスペースのセットアップ

ワークスペースの作成

npx create-nx-workspace@latest my-workspace

対話形式で以下を選択します:

  1. ワークスペースの種類: Angular(Integrated Monorepo)
  2. アプリケーション名: 最初に作成するアプリ名
  3. スタイル形式: CSS / SCSS / Less など
  4. Nx Cloud: リモートキャッシュの有効化(推奨)

ワークスペース構成

my-workspace/
├── apps/ # アプリケーション
│ └── my-app/
│ ├── src/
│ ├── project.json # プロジェクト固有の設定
│ └── tsconfig.json
├── libs/ # 共有ライブラリ
│ └── shared/
│ └── ui/
├── nx.json # Nx全体設定(キャッシュ、タスク設定)
├── tsconfig.base.json # ベースTypeScript設定
└── package.json

既存 Angular プロジェクトへの導入

# 既存のAngular CLIプロジェクトにNxを追加
npx nx init

nx init を実行すると、既存プロジェクトの構成を維持したまま、Nxのキャッシュ機能やタスク実行機能が追加されます。

3. プロジェクトとライブラリの作成

アプリケーションの作成

nx generate @nx/angular:application my-new-app

ライブラリの作成

nx generate @nx/angular:library my-lib

ライブラリの種類と命名規約

Nxのベストプラクティスでは、ライブラリを以下の種類に分類します。

種類ディレクトリ用途
featurelibs/feature/スマートコンポーネント、ページfeature-dashboard
uilibs/ui/プレゼンテーショナルコンポーネントui-button, ui-card
data-accesslibs/data-access/API通信、状態管理data-access-user
utillibs/util/ユーティリティ関数、ヘルパーutil-date, util-format
modellibs/model/インターフェース、型定義model-user, model-order
# 例: ユーザー機能のライブラリを作成
nx generate @nx/angular:library feature-user-profile --directory=libs/feature
nx generate @nx/angular:library ui-avatar --directory=libs/ui
nx generate @nx/angular:library data-access-user --directory=libs/data-access

buildable vs publishable ライブラリ

オプション説明ユースケース
buildable個別にビルド可能。キャッシュが効きやすいモノレポ内部のみで使用
publishablenpmパッケージとして公開可能外部プロジェクトでも利用するライブラリ
# publishableライブラリの作成
nx generate @nx/angular:library shared-ui --publishable --importPath=@my-org/shared-ui

4. プロジェクトグラフ(依存関係の可視化)

nx graph コマンド

# ブラウザでインタラクティブなグラフを表示
nx graph

プロジェクトグラフは、import文やTypeScriptのパスエイリアスから自動的に依存関係を検出します。

活用方法

  • アーキテクチャの俯瞰: プロジェクト全体の構造を視覚的に把握
  • 循環依存の検出: 循環参照がある場合にグラフ上で確認可能
  • 影響範囲の確認: 特定のライブラリを変更した場合の影響先を表示
# 特定プロジェクトに関連するグラフのみ表示
nx graph --focus=my-app

# 影響を受けるプロジェクトのグラフを表示
nx affected:graph

5. affected コマンド(影響範囲の特定)

affected コマンドは、Gitの差分を解析し、変更の影響を受けるプロジェクトだけを対象にタスクを実行します。

# 影響を受けるプロジェクトのみビルド
nx affected -t build

# 影響を受けるプロジェクトのみテスト
nx affected -t test

# 影響を受けるプロジェクトのみリント
nx affected -t lint

CI/CD での活用

.github/workflows/ci.yml
- name: Run affected tests
run: npx nx affected -t test --base=origin/main --head=HEAD

--base--head で比較対象のコミットを指定することで、PRごとに必要最小限のビルド・テストだけを実行できます。これにより、大規模モノレポでもCI時間を大幅に短縮できます。

6. キャッシュとリモートキャッシュ

ローカルキャッシュ

Nxは同じ入力(ソースコード + 設定)に対するタスクの結果をローカルにキャッシュします。2回目以降は実行をスキップし、キャッシュから結果を返します。

# 初回: 通常実行(数秒〜数分)
nx build my-app

# 2回目: キャッシュヒット(数ミリ秒)
nx build my-app
# > nx run my-app:build [local cache]

Nx Cloud のリモートキャッシュ

チーム全員でキャッシュを共有するために、Nx Cloudでリモートキャッシュを利用できます。

# Nx Cloudに接続
npx nx connect-to-nx-cloud

リモートキャッシュの効果:

  • チームメンバーAがビルドした結果を、メンバーBが再利用できる
  • CIで実行した結果を、ローカル開発でも再利用できる

Distributed Task Execution (DTE)

Nx Cloudの分散タスク実行は、CIパイプラインでタスクを複数のマシンに自動分散します。

.github/workflows/ci.yml
- name: Start CI run
run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js"

- name: Run tasks
run: npx nx affected -t lint test build

キャッシュ対象の設定

nx.json
{
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"]
},
"test": {
"cache": true
},
"lint": {
"cache": true
}
}
}

7. モジュール境界ルール(Module Boundaries)

@nx/enforce-module-boundaries

ESLintルールを使って、プロジェクト間の不正な依存関係を自動的に検出・禁止できます。これは大規模チームでのアーキテクチャ維持に非常に重要です。

tags によるプロジェクト分類

各プロジェクトの project.json にタグを設定します。

libs/feature/user-profile/project.json
{
"tags": ["type:feature", "scope:user"]
}
libs/ui/button/project.json
{
"tags": ["type:ui", "scope:shared"]
}

depConstraints による依存ルール

.eslintrc.json
{
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{
"sourceTag": "type:feature",
"onlyDependOnLibsWithTags": ["type:ui", "type:data-access", "type:util", "type:model"]
},
{
"sourceTag": "type:ui",
"onlyDependOnLibsWithTags": ["type:ui", "type:util", "type:model"]
},
{
"sourceTag": "type:data-access",
"onlyDependOnLibsWithTags": ["type:data-access", "type:util", "type:model"]
},
{
"sourceTag": "type:util",
"onlyDependOnLibsWithTags": ["type:util", "type:model"]
},
{
"sourceTag": "type:model",
"onlyDependOnLibsWithTags": ["type:model"]
}
]
}
]
}
}

この設定により以下のルールが強制されます:

  • feature → ui, data-access, util, model に依存可能(他の feature には依存不可)
  • ui → ui, util, model に依存可能(data-access や feature には依存不可)
  • data-access → data-access, util, model に依存可能
  • model → model のみに依存可能
React/Next.js との比較

React/Next.jsのエコシステムには、このようなモジュール境界ルールを強制する標準的な仕組みは存在しません。大規模プロジェクトでは eslint-plugin-import の制限的なルールや、独自のESLintルールを作成して対応します。

8. ジェネレータ(Generators)

Nx ジェネレータ vs Angular Schematics

機能Nx ジェネレータAngular Schematics
位置づけNxエコシステムの一部Angular CLIの一部
対象Angular、React、Node.js等マルチフレームワークAngularに特化
テストJest によるユニットテストが容易やや複雑
ドライラン--dry-run で事前確認可能同様

カスタムジェネレータの作成

チーム固有のコード生成テンプレートをジェネレータとして定義できます。

# ジェネレータ用のライブラリを作成
nx generate @nx/plugin:plugin my-plugin

# カスタムジェネレータを追加
nx generate @nx/plugin:generator my-generator --project=my-plugin

カスタムジェネレータはチーム内のボイラープレートを統一し、新しいコンポーネントやサービスを一貫した構造で自動生成するために活用します。

9. マイクロフロントエンド with Nx

NxはModule Federationを使ったマイクロフロントエンドの構築をサポートしています。

ホストとリモートの作成

# ホストアプリケーション(シェル)の作成
nx generate @nx/angular:host shell --remotes=app1,app2

# リモートアプリケーションの追加
nx generate @nx/angular:remote app3 --host=shell

Module Federation の構成

apps/shell/module-federation.config.ts
import { ModuleFederationConfig } from '@nx/webpack';

const config: ModuleFederationConfig = {
name: 'shell',
remotes: ['app1', 'app2'],
};

export default config;

共有ライブラリの管理

  • NxはModule Federation設定で共有ライブラリの重複を自動排除
  • libs/ 内のライブラリはシングルトンとして共有され、バンドルサイズを削減
  • 各リモートアプリは独立してビルド・デプロイ可能

10. CI/CD パイプラインとの統合

GitHub Actions での設定例

.github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:

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'

- run: npm ci

- uses: nrwl/nx-set-shas@v4

- run: npx nx affected -t lint test build

ポイント

  • fetch-depth: 0 で完全なGit履歴を取得(affected の差分計算に必要)
  • nrwl/nx-set-shas でベースコミットを自動設定
  • nx affected で変更の影響を受けるプロジェクトだけを対象にタスク実行

11. Nx Console(VS Code 拡張機能)

Nx Console はVS Code拡張機能として提供されており、GUIでNxの機能を操作できます。

  • ジェネレータの実行: フォーム形式でオプションを設定し、コンポーネントやライブラリを生成
  • プロジェクトグラフ: VS Code上でインタラクティブに依存関係を表示
  • タスクの実行: build / serve / test / lint をクリックで実行
  • affected の確認: 現在の変更による影響範囲を視覚的に表示
提示

詳細な活用方法は「VS Code環境構築のベストプラクティス」を参照してください。

12. 既存プロジェクトの移行

Angular CLI → Nx への段階的移行

ステップ1: Nxの追加

npx nx init

この段階では既存のプロジェクト構造はそのまま。Nxのキャッシュとタスク実行機能が追加されます。

ステップ2: ライブラリの分割

既存のモジュールを段階的にNxライブラリに分割します。

# 共有UIライブラリの作成
nx generate @nx/angular:library shared-ui --directory=libs/ui

# 既存コードをライブラリに移動
# → import パスを更新

ステップ3: 境界ルールの導入

ライブラリにタグを設定し、@nx/enforce-module-boundaries ルールを有効化して、アーキテクチャの一貫性を確保します。

移行のコツ

  • 一度にすべてを移行しようとせず、段階的に進める
  • まずキャッシュの恩恵を受けるだけでも大きな改善になる
  • ライブラリの分割は、最も頻繁に変更されるモジュールから着手する
  • CI/CDパイプラインでの nx affected の導入は早期に行うと効果的