14.08.2024

NestJS: Dinamik Modüller

NestJS uygulamalarına kendi modüllerimi yazarken pek çok durumda statik modüllerden faydalanıyorum. Daha önceki yazımda modüllerden bahsederken de sadece statik modül kullanımından bahsetmiştim. NestJS dokümanlarının pek çok yerinde de yine statik kullanım örneği ile karşılaşmanız mümkün. Dinamik modüller ile ilgili detaylı bilgiye ise doküman içindeki bu sayfadan ulaşabilirsiniz. 

Daha önceki yazımda da bahsettiğim statik modüllerin, import ve export edilerek ilişkilendirilmesine "Static Module Binding" (Statik Modül Bağlaması) deniyor. Statik bir modül import edildiğinde, olduğu gibi kullanılabiliyor olmakla birlikte, import edilen modülün yapılandırmasına etki etmek mümkün olmuyor. Ancak genel amaçlı bir modül geliştirdiğinizde ve bu modülün farklı yerlerde import edildiğinde farklı davranışlar sergilemesi gerekebiliyor. Nest'in Configuration modülünü ele alalım. Ortam değişkenlerini saklamak için kullandığımız .env dosyası tüm projelerimizde aynı yerdeyse statik bir Configuration modülü yeterli olacaktır. Ancak dosya farklı projelerde farklı yollarda yer alıyorsa bu dosya yolunu Configuration modülünü import ederken parametre olarak geçme ihtiyacı doğar. İşte dinamik modüller burada devreye giriyor.

Aşağıda ConfigModule modülünün, AppModule'e nasıl import edildiğini görebilirsiniz:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from './config/config.module';

@Module({
  imports: [ConfigModule.register({ folder: './config' })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Bir diğer örnek benim yayınladığım nestjs-imap paketinden ImapModule'un kullanımı olabilir:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ImapModule, ImapConfig } from 'nestjs-imap';
import { EmailService } from './email.service';

const imapConfig: ImapConfig = {...};

@Module({
  imports: [ImapModule.forRoot(imapConfig)],
  controllers: [AppController],
  providers: [AppService, EmailService],
})
export class AppModule {}

Config objesi ImapModule'ü, AppModule'e import edilirke parametre olarak gönderiliyor. Böylece ImapModule'ün farklı uıygulamalarda kodunda bir değişiklik yapmadan kullanılabilmesi sağlanmış oluyor.

Nestjs-Imap paketinin kodunu incelerseniz, aşağıdaki dynamic bir modülün nasıl oluşturulduğunu da görebilirsiniz:

import { DynamicModule, Module } from '@nestjs/common';
import { ImapService } from './imap.service';

@Module({})
export class ImapModule {
  static forRoot(config: ImapConfig): DynamicModule {
    return {
      module: ImapModule,
      providers: [
        {
          provide: 'IMAP_CONFIG',
          useValue: config,
        },
        ImapService,
      ],
      exports: [ImapService],
    };
  }
}

Daha karmaşık dinamik modüller içinse "Configurable module builder" kullanmak mümkün. Bu konuyla ilgili detaylı bilgiyi de dokümanın ilgili kısmında bulabilirsiniz.

Şimdilik bu kadar. Kısa bir yazı oldu ama umarım dinamik modüllere ilginizi çekebilmişimdir.

Esen kalın.