Dev Study
NestJS コース

33. 動的モジュール — forRoot パターン

ここまで使ってきた ConfigModule.forRoot(...) や TypeOrmModule.forRoot(...) は、動的モジュールという仕組みです。通常のモジュールは @Module({...}) で構成が固定ですが、動的モジュールは forRoot(options) という静的メソッドを持ち、呼び出し側から設定を受け取って、その場で providers を組み立てた DynamicModule オブジェクト({ module, providers, exports }) を返します。

実務での慣習として、アプリ全体で一度だけ設定する全体設定には forRoot、機能(リポジトリなど)ごとに繰り返し登録するものには forFeature、汎用ライブラリには register という名前を使い分けます。自作の共有ライブラリ(社内の認証モジュールやロガーモジュールなど)を「設定を渡して使ってもらう」形で配るときに、このパターンで作ります。受け取った options は useValue でトークンに載せて、モジュール内のサービスに注入できるようにするのが定番です。

つまずきポイントは、forRoot を呼ぶ場所です。forRoot は基本的にルートモジュール(AppModule)で一度だけ呼び、各機能モジュールでは設定を渡さない forFeature を使います。同じ全体設定を複数箇所で forRoot してしまうと、設定が重複して予期しない動作になりがちです。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Module, DynamicModule } from "@nestjs/common";

export type StorageOptions = { bucket: string };

@Module({})
export class StorageModule {
  // forRoot: 設定を受け取り、その場でモジュール構成を組み立てて返す
  static forRoot(options: StorageOptions): DynamicModule {
    return {
      module: StorageModule,
      providers: [
        // 渡された設定をトークンに載せて注入可能にする
        { provide: "STORAGE_OPTIONS", useValue: options },
        StorageService,
      ],
      exports: [StorageService],
    };
  }
}

// 利用側(AppModule)— 設定を渡して一度だけ登録する
@Module({
  imports: [StorageModule.forRoot({ bucket: "my-app" })],
})
export class AppModule {}
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗