【フロントエンド、バックエンドを一つのリポジトリで管理】monorepoを実現できるNxをさわってみた

どうも!大阪オフィスの西村祐二です。

フロントエンド、バックエンドを一つのリポジトリで管理したいときがあると思います。

それを簡単に実現できるNxが使い勝手よかったのでご紹介したいと思います。

monorepoとは

1つのリポジトリの中に複数のパッケージを同梱しリポジトリを運用することをmonorepoと言います。

環境構築やビルドなどのプロセスを簡単に統一できることや、 フロントエンド、バックエンドの共通処理の横断した修正が容易などメリットがあります。

特にTypeScriptの場合、型定義ファイルをフロントエンドとバックエンドで共有できて効率よく開発を進めることができるなどのメリットがあります。

Nxとは

Nxはmonorepo用の拡張可能な開発ツールです。

作っているところが、Angular Consoleなどを作っていることもあってAngularフレンドリーなかんじです。

Nxを使用すると、TypeScript、Cypress、Jest、Prettier、Angular、React、Next.js、NestJSを開発ワークフローに追加できます。

Nxはこれらのツールをセットアップし、シームレスに使用できるようにします。

似たツールとしてはlernaがあります。興味のある方はこちらもウォッチしておくと良さそうです。

試してみる

今回はAngular+NestJSの構成を作ってみます。

環境

  • Node.js:v10.15.1
  • Angular:8.2.0
  • NestJS:6.2.4
  • Nx:8.6.0

ワークスペースを作成する

demoというワークスペースを作成します。

$ npx create-nx-workspace@latest demo


すると、どの種類で作成するかきかれるので、今回は「angular-nest」を選択します。

? What to create in the new workspace
  empty             [an empty workspace]
  web components    [a workspace with a single app built using web components]
  angular           [a workspace with a single Angular application]
❯ angular-nest      [a workspace with a full stack application (Angular + Nest)]
  react             [a workspace with a single React application]
  react-express     [a workspace with a full stack application (React + Express)]
  next.js           [a workspace with a single Next.js application]

アプリケーションの名前を適当に入力します。ここでは「test」としておきます。また、スタイルシートはデフォルトのCSSにしておきます。

? Application name test

? Default stylesheet format           (Use arrow keys)
❯ CSS
  SASS(.scss)  [ http://sass-lang.com   ]
  Stylus(.styl)[ http://stylus-lang.com ]
  LESS         [ http://lesscss.org     ]

しばらくすると、作成が完了します。

これだけで、AngularとNestJSの環境の出来上がりです。

APIとアプリケーションをローカル実行してみる

さっそく動かしてみます。

$ cd demo

NestJSのAPIをローカル実行してみます。

ngコマンドで実行できます。

$ ng serve api


Starting type checking service...
Using 6 workers with 2048MB memory limit
Type checking in progress...
Hash: ede246eb2fe7b90939e2
Built at: 2019-10-14 14:08:05
Entrypoint main = main.js main.js.map
chunk {main} main.js, main.js.map (main) 2.38 KiB [entry] [rendered]
Debugger listening on ws://localhost:7777/500ec5fb-5448-44b8-bb24-4eefc50aeaa4
For help, see: https://nodejs.org/en/docs/inspector
[Nest] 93931   - 2019-10-14 14:08:06   [NestFactory] Starting Nest application...
[Nest] 93931   - 2019-10-14 14:08:06   [InstanceLoader] AppModule dependencies initialized +35ms
[Nest] 93931   - 2019-10-14 14:08:06   [RoutesResolver] AppController {/api/}: +14ms
[Nest] 93931   - 2019-10-14 14:08:06   [RouterExplorer] Mapped {/hello, GET} route +6ms
[Nest] 93931   - 2019-10-14 14:08:06   [NestApplication] Nest application successfully started +26ms
Listening at http://localhost:3333/api
No type errors found
Version: typescript 3.4.5
Time: 2551ms

問題なく動きました!

続いて、Angularのアプリケーションをローカル実行してみます。

別ターミナルで下記コマンドを実行します。

馴染みのあるngコマンドで実行します。

$ ng serve test



10% building 3/3 modules 0 activeℹ 「wds」: Project is running at http://localhost:4200/webpack-dev-server/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: 404s will fallback to //index.html

chunk {main} main.js, main.js.map (main) 29.6 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 302 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 10.1 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 3.93 MB [initial] [rendered]
Date: 2019-10-14T05:10:04.324Z - Hash: bb4ce34638b05b8e9fdd - Time: 3591ms
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
ℹ 「wdm」: Compiled successfully.

こちらも問題なく実行できました。 ブラウザにアクセスして画面を確認してみると下記のような画面が表示されました。AngularからNestJSのAPIをコールしてメッセージを受け取っていることがわかります。

構成を確認してみる

Nxで作成された構成で特徴的なところをみていきます。構成としては下記のようになっています。

AngularのアプリケーションはテストフレームワークがJest、Cypressに置き換わっているので、ご注意ください。いつも、置き換えている人にとっては手間が省けて嬉しいですね。

api

NestJSのソースが格納されています。

test, test-e2e

Angularのアプリケーションが格納されています。

NestJSと連携できるようにproxy.conf.jsonが設定されています。

{
  "/api": {
    "target": "http://localhost:3333",
    "secure": false
  }
}

api-interfaces

AngularとNestJSで共有で使う型定義ファイルがここに格納されています。

自動的に共有部分が作成されているので手間が省けて嬉しいですね。

export interface Message {
  message: string;
}

nx.json

ここでワークスペースの構成が定義されています。

プロジェクトごとにタグの設定ができ、ビルドする対象やテストする対象をタグを指定して実行できるようです。


{
  "npmScope": "demo",
  "implicitDependencies": {
    "angular.json": "*",
    "package.json": "*",
    "tsconfig.json": "*",
    "tslint.json": "*",
    "nx.json": "*"
  },
  "projects": {
    "test-e2e": {
      "tags": []
    },
    "test": {
      "tags": []
    },
    "api": {
      "tags": []
    },
    "api-interfaces": {
      "tags": []
    }
  }
}

テストを実行してみる

Angularなど触っている方なら馴染みのあるngコマンドでテスト実行できます。

AngularとNestJS両方のテストをコマンドで実行できます。

$ ng test

プロジェクトを指定するとそのプロジェクトのテストのみ実行できます

NestJSのAPIのみテスト実行
$ ng test api

Angularのみテスト実行
$ ng test <app-name>

また、AngularのE2EテストはCypressに置き換わっているので、Cypressでテストすることができます。

ng e2e <app-name>-e2e --watch

他にも、Nxでは便利なコマンドがいくつか用意されています。その中に変更したコードに影響があるプロジェクトを検出してテストを実行する、というようなコマンドがあります。

これを使ってテストにかかる時間の短縮などができそうです。

コマンドは下記になります。

$ npm run affected:test

ビルドしてみる

テスト同様、ngコマンドでビルドすることができます。

$ ng build
$ ng build api

また、変更したコードに影響があるプロジェクトを検出してビルドを実行する、というようなコマンドがあります。

$ npm run affected:build

依存関係をグラフで表示してみる

1つのリポジトリに収集することによって見通しが悪くなったり、どういった構成になっているかわかりにくくなることが予想されます。その対策のために、Nxでは依存関係をグラフで表示する機能が用意されています。

下記コマンドを実行すると依存関係を表したグラフがブラウザ上に表示されます。

$ npm run dep-graph

さいごに

Nxを使うとコマンド一発で、フロントエンド、バックエンドTypeScriptなAngular+NestJSの構成が作成できます。また、Cypress、Jest構成のテスト環境やビルド環境も揃った状態なので、すぐに開発に取りかかれます。

また、Angularだけじゃなく、React、Next.jsもサポートされています。

Angularを使っている人やバックエンドにNestJSを使っている人、またはフロントエンド、バックエンドをTypeScriptで開発していきたい人にとってはとても重宝するツールなのではないでしょうか。

興味のある方は是非試してみてください。