vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

Angular 10 + NgRx + Nest.js でプロジェクトを作る

はじめに

今回はサーバー側のプログラムも追加してみます。

今回は TypeScript 好きである、ということもあって Nest.js を選びました。

Environments

  • Angular ver.10.0.2
  • @ngrx/store ver.9.2.0
  • @ngrx/effects ver.9.2.0
  • @nestjs/ng-universal ver.2.0.1

Angular ver.10のプロジェクトに @ngrx/store が追加できない

前回同様「npx ng add @ngrx/store」で NgRx を追加しようとするとエラーが発生。

Installing packages for tooling via npm.
Installed packages for tooling via npm.
The package that you are trying to add does not support schematics. You can try using a different version of the package or contact the package author to add ng-add support.

下記の Issue によると、「@latest」をつける必要があるとのこと。

npx ng add @ngrx/store@latest

「@latest」をつけない場合、 1.2.0 のような古いバージョンのものがインストールされているようでした。

cannot use ng add to install ngrx store · Issue #2604 · ngrx/platform · GitHub

「@ngrx/effects」については「@latest」が必要かどうかはわかりませんでしたが、とりあえずつけてインストールしました。

npx ng add @ngrx/effects@latest

Nest.js のプロジェクトを追加する

「@nestjs/ng-universal」を使って Nest.js のプロジェクトを追加します。

GitHub - nestjs/ng-universal: Angular Universal module for Nest framework (node.js) 🌷

元々は Server-Side Rendering のためのものではありますが。

「ng add」コマンドを実行すると、プロジェクト名を聞かれるので先に作成した Angular のプロジェクト名を入力します。

npx ng add @nestjs/ng-universal

プロジェクトを実行する(失敗)

「npm run serve」で実行し、「localhost:4200」にアクセスするわけですが、ここでエラーが発生しました。

...
[Nest] 12736   - 07/08/2020, 1:04:45 AM   [ExceptionsHandler] Cannot read property 'indexOf' of undefined +28479ms
TypeError: Cannot read property 'indexOf' of undefined
...

下記の Issue によると、「liveReload」を false にする必要があるとのこと。

TypeError: Cannot read property 'indexOf' of undefined · Issue #188 · nestjs/ng-universal · GitHub

server/app.module.ts


import { Module } from '@nestjs/common';
import { AngularUniversalModule } from '@nestjs/ng-universal';
import { join } from 'path';

@Module({
  imports: [
    AngularUniversalModule.forRoot({
      viewsPath: join(process.cwd(), 'dist/browser'),
      bundle: require('../server/main'),
      liveReload: false
    })
  ]
})
export class ApplicationModule {}

白いページが表示される

「liveReload」自体も気になるところですが、とにあれこれでエラーなしでページを表示できました。

が、そこにあるのはただ真っ白のページ。Angular のページではありません。

プロジェクトの README.md にある「bootstrap」は(恐らく)仕様変更のため「AngularUniversalOptions」に存在せず、サンプルコードをそのままコピペすることはできないようです。

ただ、「localhost:4200/index.html」にアクセスすると、正しく Angular のページが表示できました。 f:id:mslGt:20200708021636j:plain

ということで、 デフォルトの Static file が設定されていないようだ、ということはわかりました。

またまた README.md を見ると「templatePath」というプロパティがあったため、追加してみたのですが動作しないようです。

server/app.module.ts


import { Module } from '@nestjs/common';
import { AngularUniversalModule } from '@nestjs/ng-universal';
import { join } from 'path';

@Module({
  imports: [
    AngularUniversalModule.forRoot({
      viewsPath: join(process.cwd(), 'dist/browser'),
      bundle: require('../server/main'),
      liveReload: false,
      templatePath: join(process.cwd(), 'dist/browser/index.html'),
    })
  ]
})
export class ApplicationModule {}

「@nestjs/serve-static」を使ったり、ルーティングで index.html を表示させる、といった処理が必要なのでしょうか。。。?

2020-07-08 追記

@nestjs/serve-static 追加

今回は Nest.js で静的ファイルを扱うことができるようにする「@nestjs/serve-static」を使って解決することにしました。

npm install --save @nestjs/serve-static

server/main.ts


import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);
  app.setGlobalPrefix('api');
  app.useStaticAssets(join(__dirname, '..', 'browser'));
  await app.listen(4200);
}
bootstrap();