angular
nrwl
AngularDay 11

Nxに触ってみる

この記事はAngular Advent Calendar 2017の11日目の記事です。

早速ですが、みなさんはNxというプロジェクトをご存知でしょうか?
Nrwlという、Angularのコアコントリビュータがコンサルティングやトレーニングを提供する、というサービスの中で発生したプロジェクトのです。

プロジェクトの初コミットが2017/8/10という比較的新しいプロジェクトで、2017/12/05時点でスター数が232と注目度が高いプロジェクトではありませんが、
コアコントリビュータの一人で、Change Detectionの基盤を作り上げるなど現在のAngularになくてはならないvsavkinさんが大半のコミットを行っており、どんな展開をしていくのか楽しみなプロジェクトです。

今回の記事では、このNxに触っていきたいと思います。

(なお、NxはAngularJSからのアップグレードについても機能提供があるのですが、筆者はAngularJSの開発経験がなく、AngularJSからのアップグレードについては言及が難しいので、今回は取り上げません。)

そもそもNxとは

「Nrwl Extensions for Angular」の略称で、オープンソースのエンタープライズAngularアプリケーション向けのツールキット、という位置づけプロジェクトです。

公式サイトの記載によると、エンタープライズでAngularアプリケーションを構築するチームには以下のような課題がある、としています。

  • 単一の小さなアプリを作っているわけではなく、複数のチームにまたがって複数の共有ライブラリを利用した複数のアプリケーションを作っており、その開発フローを整理するのは容易ではない。
  • それぞれのチームが独自の開発手法を取ってしまうと、コードの再利用は困難になるため、一貫性を考慮する必要がある。
  • 古いAngularJS製のアプリケーションはアップグレードする必要がある。NgUpgradeは素晴らしいが、設定ミスが起こりやすい。
  • エラー処理などで堅牢なコードが求められる。

上記の課題に対して、NrwlとしてGoogleのAngularチームの経験にもとづいて推奨構成を開発したところ、多くの箇所が自動化できることに気づき、Nxの開発に至った、というのがプロジェクト開始のきっかけのようです。

Nxのパッケージ

Nxは2つのパッケージからなります。

  • @nrwl/schematics
  • @nrwl/nx

@nrwl/schematicsはAngular CLIのプラグインとして動作します。 @nrwl/nxはソースの中でimportするライブラリです。

これらはNxが提供するリポジトリ構成に含まれています。このリポジトリ構成をNxワークスペースと呼びます。実態はAngular CLIプロジェクトを拡張したものなのですが、monorepoに対応した形で構築されており、Nxワークスペース内に複数のアプリケーションやライブラリを構築していくことができます。

実際に使ってみる

インストール

Nxには2種類のインストール方法が提供されています。

  • インストールスクリプトを利用する方法
  • npmのグローバルインストールを利用する方法

今回はお試しということで、「インストールスクリプトを利用する方法」を利用します。バージョンはstableを使いましょう。

ターミナルを開き、プロジェクトを作成したいディレクトリで以下のコマンドを入力します。

curl -fsSL https://raw.githubusercontent.com/nrwl/nx/master/packages/install/install.sh | bash -s sampleproject

するとプロジェクトのダウンロードが始まり、一見Angular CLIプロジェクトによく似た構成のプロジェクトが出来上がります。

Nxワークスペースの作成はこれだけです。
あとはこのプロジェクトにアプリケーションやライブラリを追加していきます。

ライブラリを作成する

ここで、先程紹介した @nrwl/schematicsを利用します。

作成したNxワークスペース内に移動し、以下のコマンドを入力します。

ng g lib foo

'lib'が@nrwl/schematicsで追加されたテンプレートの一つです。実行すると、Nxワークスペース直下の「libs」フォルダ内に「foo」フォルダが作成されたと思います。

@angular/routerを利用したい場合は通常のAngular CLI同様「--routing」オプションが利用できます。

ng g lib bar --routing

デフォルトではAngularのモジュールを生成しますが、「--nomodule」オプションを利用すればAngularモジュールを生成しないことも可能です。関数ライブラリなどで利用できそうですね。

アプリケーションを作成する

当然のことながら、ライブラリを利用するアプリケーションも作成できます。

ライブラリを作成した時と同じようにNxワークスペースに移動し、以下のコマンドを入力します。

ng g app sample

ここでいう'app'も@nrwl/schematicsによって追加されたテンプレートです。実行すると、Nxワークスペース直下の「apps」フォルダ内に「sample」フォルダが作成されます。ライブラリを作成したときに比べると、index.htmlやmain.ts、polyfills.tsなどが増え、従来のAngular CLIでプロジェクトを作成したものに近いファイル構成であることが分かります。

なお、'lib'テンプレートの場合と同様に「--routing」オプションが利用可能です。

コンポーネントを作成する

これまででライブラリ、アプリケーションをコマンドで作成することはできましたが、sampleアプリケーションにはapp.component.tsしかありませんので、試しにコンポーネントを追加してみます。

Nxワークスペース上でコンポーネントなどのソースを追加する場合は、通常のAngular CLIのコマンドに「--app」オプションを付けて追加先のプロジェクトを指定する必要があります。

以下のコマンドを実行してみます。

ng g component sample-label --app=sample

実行すると自動的に「apps/sample」配下にコンポーネントが追加され、通常のAngular CLI同様にNgModuleの定義も更新されます。オプションが増えただけで通常と全く変わらない感覚でコンポーネントを追加することができました。

なお、'libs'配下に追加したい場合も「--app」オプションです。(「--lib」オプションはないので注意して下さい。」

アプリケーションからライブラリを読み込む

Nxワークスペース上に複数のアプリケーション、ライブラリを作成する方法を学んだので、次はこれらを連動させて行きましょう。

まずはng g component foo --app=fooを実行してfooライブラリにコンポーネントを追加し、作成された「libs/foo/src/foo/foo.component.html」を以下のように編集します。

<p>
  foo module works!
</p>

また、このfooコンポーネントをこのライブラリを使用するアプリケーションに公開するため、「libs/foo/src/foo.module.ts」のexportsに定義を追加します。

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FooComponent } from './foo/foo.component';

@NgModule({
  imports: [CommonModule],
  declarations: [FooComponent],
  exports: [FooComponent]        // <- 追加
})
export class FooModule { }

次に、このモジュールをsampleアプリケーションから読み込みます。
「apps/sample/src/app/app.module.ts」を以下のように編集して下さい。

import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { NxModule } from '@nrwl/nx';
import { FooModule } from '@sampleproject/foo';    // <- 追加
import { SampleLabelComponent } from './sample-label/sample-label.component';

@NgModule({
  imports: [
    BrowserModule,
    NxModule.forRoot(),
    FooModule    // <- 追加
  ],
  declarations: [AppComponent, SampleLabelComponent ],
  bootstrap: [AppComponent]
})
export class AppModule { }

モジュールのimportが「@sampleproject/foo」から行えているのが分かります。(この'sampleproject'はNxワークスペースを作成したときに指定した名称です。)

このような形にしておくと、例えばこのあとさらにアプリケーションを追加して、そのアプリケーションからもfooライブラリを使う、という場合もsampleアプリケーションには影響を及ぼすことなく簡単に追加することができます。非常に便利ですね。

NgRxを使う

ここまでは単一リポジトリ内に複数のプロジェクトを作るための機能について紹介してきましたが、Nxは他にもテンプレートを提供しており、RxJSを利用したReduxライクな状態管理ライブラリである、NgRx向けのテンプレートも提供しています。

状態管理のライブラリとして本家ReduxやVue.js版実装であるVuexなど多くのJavaScriptフレームワーク向けの実装が登場し、人気が確立しつつある印象がありますが、実際使ってみるとボイラープレート的なコードが多く導入までが少し面倒な印象ですが、@nrwl/schematicsがテンプレートの生成までを行ってくれます。

以下のコマンドを実行します。

ng g ngrx sample --module=apps/sample/src/app/app.module.ts --root

すると指定したモジュールのフォルダ配下に「+sample」フォルダが作成され、以下のファイルが追加されます。

  • sample.actions.ts
  • sample.effects.spec.ts
  • sample.effects.ts
  • sample.init.ts
  • sample.interfaces.ts
  • sample.reducer.spec.ts
  • sample.reducer.ts

action、interface、reducerとNgRxを使う上でのボイラープレートが作成されました。
effectsはNgRxで副作用を扱う @ngrx/effects用の定義を行うファイルです。

ちなみに上記コマンドにおける「--root」オプションはアプリケーションのルートであることを示すオプションです。このオプションを付けて実行すると、そのNgModuleに対してNgRxのモジュールをインポートする定義が追加されるようになっています。

ライブラリなど、別のライブラリやモジュールから読み込んで利用される場合は「--root」オプションは不要です。

Nxの使い所

かなり手軽に試せるので導入に身構える必要はないかもしれませんが、

  • Angular CLIの最新版への対応に若干のラグがある(執筆時点でNxのデフォルトは1.5)
  • VSCodeの補完が完全に対応しきれていない

という点がありますので、気になる人は避けたほうが良いでしょう。

また、そもそも「エンタープライズ向け」と言われていますので、個人向けの小さなプロジェクトでの採用は当然ながら大きすぎと言えるでしょう。
とはいえ、公式メンバの推奨構成が手軽に得られるのは大きなメリットではないでしょうか。

おわりに

英語訳など、おかしい点があればご指摘お願いします。
明日はkouMatsumonoさんです。

リンク

Nx - Nrwl
nrwl/nx - Github