NestJSでAngularUniversalを導入する

AngularのSSRをNestJSで実現する方法についてです。

サーバサイドにNestJSをフロントにAngularかつSSRをするアーキテクチャを考えています。
が、NestJSの記事がなさすぎて苦戦したので記事にしておこうと思って記載しています。


## 動作環境
Angular CLI: 8.3.17
Node: 12.3.1
Angular: 8.2.13


## SSR設定手順

### Angularワークスペース作成
まずは普通にAngularワークスペースを作成します。
今回のサンプルプログラムではroutingを設定して、stylesheetはCSSにします。
また、今回のワークスペース名は`nest-angular-ssr`にしましたが、ご自由に設定してください。

```console:
$ ng new nest-angular-ssr
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
```

### AngularUniversalのインストール

作成したワークスペースに移動して、AngularUniversalをインストールします。

NestJS用のAngularUniversal `nest/universal`が用意されていますので、こちらをインストールします。
この時、ワークスペース名を聞かれるので、最初に`ng new (ワークスペース名)`で設定したものを入力してください。

```console:
$ cd nest-angular-ssr/
$ ng add @nestjs/ng-universal
Skipping installation: Package already installed
? What is the name of your application? nest-angular-ssr
```

なんとこれで完成です。
作成されたディレクトリはこのようになっています。(1階層だけ記載します)

```console:
$ tree -L 1
.
├── README.md
├── angular.json
├── browserslist
├── dist
├── e2e
├── karma.conf.js
├── node_modules
├── package-lock.json
├── package.json
├── serve-script.js
├── server
├── src
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.server.json
├── tsconfig.spec.json
├── tslint.json
└── webpack.server.config.js
```

serverディレクトリには、NestJSのソースが入っています。
srcディレクトリは、Angularのソースです。


### 実行してみる

デフォルトで用意されているhtmlファイルだとわかりにくいので、`app.component.html`ファイルを簡単なものに書き換えてみます。

```html:src/app/app.components.html
 <span>{{ title }} app is running!</span>
```

こちらは参考までにComponentsファイルの内容です。
titleに`nest-angular-ssr`が設定されています。

```javascript:src/app/app.components.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'nest-angular-ssr';
}
```

では実行します。

```console:
$ npm run serve
```

### SSR確認

`http://localhost:4200`に接続することで、作成したアプリケーションが実行されます。
Chrome上で、view-soure:localhost:4200を実行することで、JavaScriptが実行される前のサーバ側から返却されたHTMLが確認できます。
`<span _ngcontent-sc0="">nest-angular-ssr app is running!</span>` の部分がSSRして生成されたHTMLです。

|![markdown-mark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406169/7c99e42b-033a-3642-0635-7a3c2d29e211.png)|
|:-:|

これでSSR成功を確認できました！
すごく簡単です。


## NestJS
参考までにNestJSでAPIも作成してみます。

serverディレクトリに移動し、コントローラを作成します。

```console:
$ cd server
$ nest g controller cats
CREATE /src/cats/cats.controller.spec.ts (479 bytes)
CREATE /src/cats/cats.controller.ts (97 bytes)
UPDATE /app.module.ts (454 bytes)
```

作成されたコントローラを修正します。

```javascript:server/src/cats/cats.controller.ts
import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}
```

では実行します。

```console:
$ npm run serve
```

### NestJSの実行結果確認

`http://localhost:4200/api/cats`に接続することで、APIが実行されます。
catsコントローラに設定した値が返却されていることを確認できました！

|![markdown-mark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406169/b15a762a-4e59-da29-7f8b-8c4983874afd.png)|
|:-:|


##  参考記事
[Nest.jsでコントローラ・サービスを作ってみる]
(https://qiita.com/YutaSaito1991/items/a26b7a96b2b1c7dd540a)

#### その他
手前味噌ですが、、、
AngularUniversalでSSRを行った際に、クライアントとサーバで2回処理してるどうしよう・・・と困ったら以下記事を参考にしてください。
[AngularUniversalでクライアントとサーバで2回APIを実行しないようにする](https://qiita.com/YutaSaito1991/items/3de2262685ab22e36d70)