Contents
Nx の基本概念とモノレポのメリット
Nx は マルチパッケージを単一リポジトリで管理 できるモノレポツールです。
このセクションでは、Nx が提供するビルドキャッシュ・依存関係可視化・ライブラリ共有という三本柱が、開発効率と保守性にどのような効果をもたらすかを解説します。
ビルドキャッシュによる高速化
Nx はタスク(build、test、lint など)の出力をハッシュ化し、ローカルまたは Nx Cloud の分散キャッシュ に保存します。同一入力が検知された場合は再計算せずに結果を取得できるため、ビルド時間の大幅短縮が期待できます。
- 公式ベンチマークでは、Nx Cloud を利用した場合 最大約 70% のビルド時間削減 が報告されています(※Nx Cloud Benchmark)。
- キャッシュは
node_modules/.cache/nxに保存され、CI 環境でも同様に再利用可能です。
依存関係の可視化と影響範囲分析
nx graph コマンドでプロジェクト間の依存グラフを生成し、SVG として出力できます。これにより、どのライブラリがどのアプリケーションで使用されているか一目で把握でき、変更による影響範囲を正確に特定できます。
|
1 2 3 |
nx graph # UI でインタラクティブに表示 nx affected --target=build # 変更された部分だけをビルド |
ライブラリ共有でコード再利用
共通の UI コンポーネントやユーティリティは libs/ 配下に Nx ライブラリ として切り出すことで、複数アプリからインポート可能になります。依存関係が明示的になるため、重複コードの削減とテストカバレッジ向上が自然に実現します。
ポイントまとめ
ビルドキャッシュ・可視化・ライブラリ共有は、開発スピードと保守性を同時に高める Nx の核となる機能です。次のセクションでは、安全な移行手順をご紹介します。
移行前の準備:環境チェックとバックアップ
Angular プロジェクトを Nx モノレポへ移行する際は、ツールチェーンのバージョン統一 と リポジトリの安全なスナップショット取得 が成功の鍵です。このセクションでは、必要な前提条件とバックアップ手順を具体的に示します。
必要な Node・パッケージマネージャーのバージョン
| ツール | 推奨バージョン | 確認コマンド |
|---|---|---|
| Node | 20.x 系 | node -v |
| npm | ≥ 10 | npm -v |
| Yarn (任意) | ≥ 1.22 | yarn -v |
|
1 2 3 4 |
# 例: バージョンが期待通りか確認 $ node -v # v20.12.0 $ npm -v # 10.5.0 |
Angular CLI と Git の要件
- Angular CLI は既存プロジェクトと同等以上(例: 16.x 以上)をインストールしてください。
- Git は 2.30 以降であれば、フックやサブモジュールの取り扱いに問題はありません。
|
1 2 3 |
ng version # Angular CLI: 16.x 以上推奨 git --version # >= 2.30 |
バックアップと不要ファイルの整理
- クリーンなブランチを作成
bash
git checkout -b migrate-to-nx - リポジトリ全体をバンドル化(復元が必要になった場合に便利)
bash
git bundle create project-backup.bundle --all - ビルド成果物や依存ディレクトリは
.gitignoreに追記
|
1 2 3 4 |
/dist /node_modules /.nx |
ポイントまとめ
バージョン整合性と安全なバックアップが確保できたら、次は Nx ワークスペースの作成へ進みます。
Nx ワークスペース作成と既存 Angular プロジェクトのインポート
この章では、空の Nx ワークスペースを生成し、既存の Angular アプリケーションを移行する手順 を段階的に示します。重要なのは、Nx が自動で生成するメタデータ(workspace.json・project.json)と、手作業で調整が必要なパスエイリアスやビルド設定です。
1. 空ワークスペースの作成
以下のコマンドは「空」テンプレートをベースに、SCSS と組織スコープ(@myorg)を設定します。
|
1 2 3 4 5 6 |
npx create-nx-workspace my-monorepo \ --preset=empty \ --style=scss \ --npmScope=@myorg cd my-monorepo |
| オプション | 説明 |
|---|---|
--preset=empty |
何も生成しない最小構成のワークスペース |
--style=scss |
デフォルトスタイルシートを SCSS に設定 |
--npmScope=@myorg |
ライブラリインポート時に使用するスコープ |
2. プレースホルダーアプリの生成
Nx の Angular スキーマを使って、移行対象となるアプリ用の雛形ディレクトリを作ります。
|
1 2 3 4 5 |
nx g @nrwl/angular:application legacy-app \ --routing=true \ --style=scss \ --projectNameAndRootFormat=as-provided |
legacy-appは後で既存コードに置き換えるプレースホルダーです。--projectNameAndRootFormat=as-providedにより、フォルダ構造はapps/legacy-appになります。
3. コードの手動コピーと設定ファイルの調整
(a) ソースコードの移行
|
1 2 3 |
# 既存リポジトリから src ディレクトリを丸ごとコピー cp -R ../old-project/src/* apps/legacy-app/src/ |
(b) パスエイリアスの統合
tsconfig.base.json に全プロジェクト共通のエイリアスを定義し、個別 tsconfig.app.json はそれを継承させます。
|
1 2 3 4 5 6 7 8 9 10 11 |
// tsconfig.base.json(抜粋) { "compilerOptions": { "baseUrl": ".", "paths": { "@myorg/shared/*": ["libs/shared/src/index.ts"], "@myorg/legacy-app/*": ["apps/legacy-app/src/app/*"] } } } |
(c) workspace.json の微調整
自動生成されたエントリを確認し、ビルド・テスト・Lint 用のターゲット設定を旧 angular.json の内容に合わせます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// workspace.json の一部例 { "projects": { "legacy-app": { "root": "apps/legacy-app", "sourceRoot": "apps/legacy-app/src", "projectType": "application", "targets": { "build": { "executor": "@nrwl/angular:webpack-browser", "options": { "outputPath": "dist/apps/legacy-app", "index": "apps/legacy-app/src/index.html", "main": "apps/legacy-app/src/main.ts", "polyfills": "apps/legacy-app/src/polyfills.ts", "tsConfig": "apps/legacy-app/tsconfig.app.json", "webpackConfig": "apps/legacy-app/webpack.config.js" } }, // serve, test, lint も同様に定義 } } } } |
(d) カスタム Webpack 設定例
Nx の Angular ビルダーは webpack.config.js をプロジェクト単位で上書き可能です。以下は SVG ローダー と 環境変数注入 のサンプルです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// apps/legacy-app/webpack.config.js const { merge } = require('webpack-merge'); module.exports = (config, context) => { return merge(config, { module: { rules: [ { test: /\.svg$/, use: ['@svgr/webpack'] } ] }, plugins: [ new context.webpack.DefinePlugin({ 'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000') }) ] }); }; |
ポイントまとめ
空ワークスペース → プレースホルダーアプリ生成 → ソースコードコピー・設定統合 の流れで、既存 Angular プロジェクトは安全に Nx にインポートできます。
設定統合とビルド・テスト・Lint の検証
移行が完了したら、TypeScript、ESLint、Prettier の共通設定を Nx 標準へ置き換え し、各タスクが期待通りに動作するか確認します。ここでは、設定ファイルの継承構造と実際のコマンド例を示します。
TypeScript 設定の継承構造
全プロジェクトは tsconfig.base.json を基盤にし、個別アプリはそれを extends で参照します。これによりパスエイリアスやコンパイラオプションが一元管理できます。
|
1 2 3 4 5 6 7 8 9 10 11 |
// apps/legacy-app/tsconfig.app.json { "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "types": [] }, "files": ["src/main.ts", "src/polyfills.ts"], "include": ["src/**/*.d.ts"] } |
ESLint の統合
Nx が提供する Angular 用プラグインをベースに、ルートレベルで共通設定を定義し、プロジェクトごとにオーバーライド可能にします。
|
1 2 |
npm install -D @nrwl/linter eslint |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// .eslintrc.json(ルート) { "root": true, "ignorePatterns": ["!**/*"], "plugins": ["@nrwl/nx"], "overrides": [ { "files": ["*.ts", "*.tsx"], "extends": ["plugin:@nrwl/nx/angular"] }, { "files": ["*.html"], "extends": ["plugin:@angular-eslint/template-recommended"] } ] } |
プロジェクト固有の追加ルールは apps/legacy-app/.eslintrc.json に記述し、extends: ['./../../.eslintrc.json'] で継承します。
Prettier の統一
|
1 2 |
npm install -D prettier @nrwl/prettier |
|
1 2 3 4 5 6 7 8 |
// .prettierrc(ルート) { "singleQuote": true, "trailingComma": "all", "printWidth": 100, "semi": true } |
ビルド・テスト・Lint の実行と比較
| コマンド | 期待される出力例 | 移行前との主な違い |
|---|---|---|
nx build legacy-app |
> nx run legacy-app:build → 成功、dist/apps/legacy-app に成果物 ※2 回目以降は From cache 表示 |
キャッシュ利用により二回目以降のビルドが数秒で完了 |
nx test legacy-app --codeCoverage |
Jest が起動し、カバレッジレポート (coverage/) が生成 |
Karma → Jest に置き換えることで高速化・モジュールモックが容易に |
nx lint legacy-app |
ESLint の警告・エラーが一覧表示 | 重複設定除去で報告件数が減少、統一ルールに基づく品質向上 |
ポイントまとめ
tsconfig・ESLint・Prettier を根本的に統合すれば、Nx が提供する incremental build / affected コマンド の恩恵を最大限に受けられます。
Nx Cloud と CI/CD の組み込み、トラブルシューティング、移行後の整理
Nx Cloud の有効化とキャッシュ設定
Nx Cloud は分散キャッシュとリモートタスク実行を提供し、CI 環境でもローカル同様に高速化できます。公式ベンチマーク(上記参照)では、CI ビルド時間が 30% 以上短縮 されるケースが報告されています。
|
1 2 |
nx g @nrwl/nx-cloud:init # 対話形式で Free tier を選択 |
実行後、nx.json に以下が追記されます(トークンはシークレットとして管理)。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "tasksRunnerOptions": { "default": { "runner": "@nrwl/nx-cloud", "options": { "accessToken": "YOUR_NX_CLOUD_TOKEN", "canTrackAnalytics": false, "showUsageWarnings": true, "parallel": 3 } } }, "cacheableOperations": ["build", "test", "lint"] } |
CI パイプラインでの nx affected 活用例
GitHub Actions (.github/workflows/ci.yml)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
name: CI on: push: branches: [ main ] pull_request: jobs: build-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v3 with: node-version: '20' - run: npm ci - name: Set Nx Cloud token env: NX_CLOUD_TOKEN: ${{ secrets.NX_CLOUD_TOKEN }} run: echo "NX_CLOUD_TOKEN=$NX_CLOUD_TOKEN" >> $GITHUB_ENV - name: Affected Build & Test run: | nx affected --target=build --base=origin/main~1 --parallel nx affected --target=test --base=origin/main~1 --codeCoverage |
GitLab CI (.gitlab-ci.yml)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
stages: - install - build - test install: image: node:20 script: - npm ci artifacts: paths: - node_modules/ build: stage: build script: - npx nx affected --target=build --base=$CI_MERGE_REQUEST_TARGET_BRANCH_NAME needs: [install] test: stage: test script: - npx nx affected --target=test --base=$CI_MERGE_REQUEST_TARGET_BRANCH_NAME needs: [install] |
Azure Pipelines (azure-pipelines.yml)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
trigger: - main pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '20.x' - script: npm ci displayName: 'Install dependencies' - script: npx nx affected --target=build --base=$(System.PullRequest.TargetBranch) displayName: 'Affected Build' - script: npx nx affected --target=test --base=$(System.PullRequest.TargetBranch) --codeCoverage displayName: 'Affected Test' |
よくあるエラーと対処法
| エラー例 | 原因 | 解決策 |
|---|---|---|
| Circular dependency detected | ライブラリ間で相互インポートが発生 | nx dep-graph で循環を可視化し、共通ロジックを新しい共有ライブラリへ切り出す |
| Cannot find module '@myorg/shared' | tsconfig.base.json の "paths" が Webpack に反映されていない |
apps/legacy-app/webpack.config.js で resolve.alias を追加、または npm run nx reset 後に再ビルド |
| Environment variable undefined in CI | Nx はキャッシュ生成時の環境変数を保持するが、CI のシークレット設定が抜けている | GitHub Actions 等で env: に明示的に渡すか、.env ファイルを nx run-many 前にコピー |
移行後のコードベース整理
-
共通機能はライブラリ化
bash
nx g @nrwl/angular:library ui --directory=shared --style=scss
nx g @nrwl/workspace:library utils --directory=shared -
タグ付けで依存境界を管理(
project.jsonのtags)
json
// libs/ui/project.json
{
"tags": ["scope:frontend", "type:ui"]
} -
affected コマンドの定期的活用
- ローカル開発時は
nx affected --target=buildで差分ビルド。 - PR の CI では同コマンドに
--parallelオプションを付与し、リソースを有効活用。
ポイントまとめ
Nx Cloud とnx affectedを組み合わせることで、CI/CD パイプラインのビルド時間が大幅に削減できます。エラーは依存可視化と環境変数管理で未然に防げます。
まとめとブランド価値提案
技術的な総括
- モノレポ によるコード共有と依存関係の明示化で、開発速度・保守性が向上。
- インクリメンタルビルド・キャッシュ がビルド時間を最大約 70% 短縮(公式ベンチマーク参照)。
- Nx Cloud + affected コマンド による CI 最適化で、パイプライン全体のスループットが改善。
ビジネス視点での価値提案(ブランドメッセージ)
[貴社名] が Nx を導入することで実現できること
- 開発サイクルの短縮:分散キャッシュと差分ビルドにより、リリース頻度を 2 倍以上に。
- 品質向上:統一された ESLint/Prettier とモジュール境界の強制で、コードベース全体の健全性が向上。
- スケーラビリティ:数十から数百のアプリ・ライブラリを同一リポジトリで管理でき、組織横断的なコンポーネント再利用が促進される。
このように Nx は単なるツール以上に、開発プロセス全体を最適化し、ビジネス価値を直接引き上げる基盤 です。ぜひ貴社の次期プロジェクトで試してみてください。
本稿は 2024 年 10 月時点の公式ドキュメントおよびベンチマーク情報に基づいています。最新情報は https://nx.dev をご参照ください。