NestJS-API-er for virksomhetsbackend · leksjon

Moduler lastet inn ved behov og funksjonsbrytere

Last inn valgfrie funksjonsmoduler ved behov med LazyModuleLoader for å redusere oppstartskostnaden.

Leksjon 3 av 413 trinn

Moduler lastet inn ved behov og funksjonsbrytere er en gratis leksjon i NestJS-API-er for virksomhetsbackend på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i NestJS-API-er for virksomhetsbackend, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i NestJS-API-er for virksomhetsbackend inneholder totalt 4 leksjoner.

Hvorfor ivrig lasting skader oppstarten

Som standard oppretter NestJS hver modul i imports-grafen under oppstart. For et enterprise-API med dusinvis av valgfrie funksjoner — en PDF-eksportør, en betalingsgateway eller en AI-poengmotor — betyr det at De betaler hele kostnaden for oppretting av leverandører og oppvarming av tilkoblinger før appen i det hele tatt tar imot en forespørsel.

  • Tunge SDK-er (Stripe, AWS, gRPC-klienter) kjører konstruktørene sine ivrig.
  • Moduler som den aktuelle utrullingen aldri bruker, lastes likevel inn.
  • Ventetiden ved kaldstart øker lineært med modulgrafen.

Løsningen er å laste utvalgte feature-moduler lat, først når de brukes for første gang.

LazyModuleLoader

Nest leveres med en innebygd LazyModuleLoader (fra @nestjs/core). Den injiseres som enhver annen provider, og deretter kaller De load() med en factory som returnerer modulen. Nest registrerer modulens providere ved behov og mellomlagrer den resulterende referansen for senere kall.

Viktige egenskaper:

  • Lazy-moduler står ikke oppført i noen imports-array.
  • De registrerer ikke controllere, resolvere eller enhancere – bare providere.
  • Det første kallet til load() oppretter instansen; senere kall returnerer den mellomlagrede ModuleRef.
import { Injectable } from '@nestjs/common';
import { LazyModuleLoader } from '@nestjs/core';

@Injectable()
export class ReportsService {
  constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}

  async generate(): Promise<void> {
    const { PdfModule } = await import('./pdf/pdf.module');
    const moduleRef = await this.lazyModuleLoader.load(() => PdfModule);
    // moduleRef now exposes PdfModule's providers
  }
}

Hente en provider fra lazy-modulen

Objektet som returneres av load(), er en ModuleRef. Bruk metoden get() til å hente en konkret provider fra den nylig innlastede modulen. Ettersom lazy-moduler er isolerte, må De be om en provider først etter at modulen er lastet inn.

For request-scoped- eller transient-providere bruker De moduleRef.resolve() i stedet for get().

async generate(): Promise<Buffer> {
  const { PdfModule } = await import('./pdf/pdf.module');
  const moduleRef = await this.lazyModuleLoader.load(() => PdfModule);

  const pdfService = moduleRef.get(PdfService);
  return pdfService.render({ title: 'Invoice' });
}

Det er dynamisk import() som sparer plass

Den reelle gevinsten ved oppstart kommer av å kombinere LazyModuleLoader.load() med en dynamisk import(). En statisk import på toppnivå trekker modulen – og alle tunge transitive avhengigheter – inn i bootstrap-bundlen. En dynamisk import() utsetter evalueringen av filen til kallet utføres.

  • Statisk import { PdfModule } øverst i filen = lastes inn ved oppstart.
  • await import('./pdf/pdf.module') inne i metoden = lastes inn første gang den brukes.

Importer derfor alltid filen til lazy-modulen dynamisk, aldri statisk.

Definisjon av en minimal feature-modul

Selve lazy-modulen er en vanlig @Module – det er ingenting spesielt i dekortøren. Det som gjør den lazy, er utelukkende hvordan den brukes (via LazyModuleLoader i stedet for en imports-array).

Hold providerne i modulen selvstendige, slik at innlasting av den ikke trekker inn hele appen.

import { Module } from '@nestjs/common';
import { PdfService } from './pdf.service';

@Module({
  providers: [PdfService],
  exports: [PdfService],
})
export class PdfModule {}

Bufring gjør gjentatte innlastinger billige

Nest opprettholder internt et register over allerede innlastede lazy-moduler, indeksert etter resultatet fra factoryen. Det betyr at gjentatte kall til load() med samme modulk klasse i praksis er kostnadsfrie etter det første kallet – ingen dobbelt instansiering og ingen dupliserte tilkoblinger.

De kan derfor trygt kalle load() direkte i en handler med høy belastning uten å beskytte kallet selv; rammeverket dedupliserer. Kostnaden som oppstår én gang, betales ved den første forespørselen som trenger funksjonen.

Feature toggles: styr innlastingen

Feature toggles og lazy loading passer naturlig sammen. I stedet for å registrere moduler betinget ved kompilering sjekker De et flagg ved kjøring og kaller bare load() for modulen når flagget er aktivert. En deaktivert funksjon koster da ingenting – ikke engang konstruktøren.

  • Flagg fra miljøvariabler, en konfigurasjonstjeneste eller en ekstern flaggtilbyder (LaunchDarkly, Unleash).
  • Hvis toggle-en er deaktivert, avslutter De tidlig før importen.
@Injectable()
export class ExportService {
  constructor(
    private readonly lazyModuleLoader: LazyModuleLoader,
    private readonly flags: FeatureFlagService,
  ) {}

  async export(payload: ExportDto) {
    if (!this.flags.isEnabled('pdf-export')) {
      throw new ForbiddenException('Feature disabled');
    }
    const { PdfModule } = await import('./pdf/pdf.module');
    const ref = await this.lazyModuleLoader.load(() => PdfModule);
    return ref.get(PdfService).render(payload);
  }
}

En minimal flaggtjeneste (frittstående)

En feature-flag-sjekk er bare et deterministisk oppslag. Her er en rammeverksuavhengig versjon som De kan analysere og teste isolert – den samme logikken som en Nest FeatureFlagService ville pakket inn. Den leser et flaggkart og bruker en standardverdi når nøkkelen er ukjent.

class FeatureFlags {
  constructor(private readonly flags: Record<string, boolean>) {}

  isEnabled(key: string, fallback = false): boolean {
    return this.flags[key] ?? fallback;
  }
}

const flags = new FeatureFlags({ 'pdf-export': true, 'ai-scoring': false });

console.log(flags.isEnabled('pdf-export'));   // true
console.log(flags.isEnabled('ai-scoring'));   // false
console.log(flags.isEnabled('unknown', true)); // true (fallback)

Controllere og enhancere ignoreres

En viktig begrensning er at Nest bare registrerer providere når en modul lastes inn lazy. Følgende hoppes bevisst over:

  • controllers – ingen nye HTTP-ruter blir tilgjengelige.
  • Globale guards, interceptorer, pipes og filtre som er deklarert i modulen.
  • GraphQL-resolvere.

En lazy-modul kan derfor ikke legge til endepunkter. Eksponer funksjonen gjennom en controller i en eager-lastet modul som videresender til provideren som er lastet lazy.

@Controller('reports')
export class ReportsController {
  constructor(private readonly reports: ReportsService) {}

  @Post('pdf')
  async pdf(@Body() dto: ExportDto) {
    // controller is eager; PdfModule is loaded lazily inside the service
    return this.reports.generate(dto);
  }
}

Oppvarming eller lazy loading: velg per funksjon

Lazy loading bytter en engangs forsinkelse ved den første forespørselen mot en raskere og lettere oppstart. Det er riktig valg for sjeldent brukte, kostbare funksjoner. For funksjoner i den kritiske banen unngår eager loading (eller eksplisitt oppvarming i onApplicationBootstrap) å belaste den første brukeren.

Veiledning for valget:

  • Lazy: tung SDK, brukes av <X% av forespørslene, valgfri per utrulling.
  • Eager: kjernedomene, hver forespørsel, følsom for latenstid.
  • Lazy + oppvarming: tung, men forutsigbart nødvendig kort tid etter oppstart.
@Injectable()
export class Warmer implements OnApplicationBootstrap {
  constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}

  async onApplicationBootstrap() {
    if (process.env.PRELOAD_PDF === 'true') {
      const { PdfModule } = await import('./pdf/pdf.module');
      await this.lazyModuleLoader.load(() => PdfModule); // pay cost now, off the request path
    }
  }
}

Mål gevinsten

Kvantifiser før og etter. Mål tiden for oppstart og det første lazy-kallet til load() for å bekrefte at avveiningen faktisk lønner seg for arbeidsbelastningen Deres.

  • Oppstartstiden bør reduseres med den samlede kostnaden for konstruktører og tilkoblinger i modulene som utsettes.
  • Latenstiden ved det første kallet til lazy-funksjonen absorberer denne kostnaden én gang.
  • Følg med på P99 for den første forespørselen etter utrulling – det er der den utsatte kostnaden blir synlig.

Hvis lazy-funksjonen brukes ved nesten hver forespørsel, vil tallene vise at De bør bytte tilbake til eager loading.

const t0 = performance.now();
const { PdfModule } = await import('./pdf/pdf.module');
const ref = await this.lazyModuleLoader.load(() => PdfModule);
this.logger.log(`Lazy PdfModule ready in ${Math.round(performance.now() - t0)}ms`);

Kunnskapssjekk

De laster inn PdfModule lazy via LazyModuleLoader. PdfModule deklarerer en controller med en @Post('pdf')-rute. Etter innlastingen returnerer ruten 404. Hva er riktig forklaring og løsning?

Oppsummering

De har lært hvordan De kan redusere oppstartskostnaden i NestJS med moduler som lastes inn ved behov:

  • LazyModuleLoader.load(() => SomeModule) oppretter modulens providere første gang de brukes og mellomlagrer resultatet.
  • Kombiner dette med en dynamisk import(), slik at modulens fil (og tunge avhengigheter) aldri evalueres under bootstrap.
  • Hent providere via moduleRef.get() (eller resolve() for scoped-providere).
  • Feature toggles styrer innlastingen: En deaktivert funksjon koster ingenting, ikke engang en konstruktør.
  • Lazy-moduler registrerer ingen controllere, resolvere eller enhancere – la en eager-lastet controller videresende til dem.
  • Velg lazy for tunge, sjeldent brukte og valgfrie funksjoner; eager (eller lazy + oppvarming) for kode i den kritiske banen. Mål oppstartstid og latenstid ved første kall for å bekrefte valget.
Gratis å komme i gang

Lær deg TypeScript med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
20
Leksjoner
76

Ofte stilte spørsmål

Er leksjonen «Moduler lastet inn ved behov og funksjonsbrytere» gratis?

Ja – hele teksten i «Moduler lastet inn ved behov og funksjonsbrytere» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av NestJS-API-er for virksomhetsbackend-kurset, kan du oppgradere til CoddyKit PRO. Kurset i NestJS-API-er for virksomhetsbackend inneholder totalt 4 leksjoner.

Hva lærer jeg i «Moduler lastet inn ved behov og funksjonsbrytere»?

Last inn valgfrie funksjonsmoduler ved behov med LazyModuleLoader for å redusere oppstartskostnaden. Du øver på NestJS-API-er for virksomhetsbackend med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med NestJS-API-er for virksomhetsbackend?

Ingen tidligere erfaring er nødvendig. NestJS-API-er for virksomhetsbackend på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Moduler lastet inn ved behov og funksjonsbrytere»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne NestJS-API-er for virksomhetsbackend-leksjonen?

Ja. Alle NestJS-API-er for virksomhetsbackend-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Porter og adaptere for domeneisolasjon
  2. Dynamisk registrering av providere med DiscoveryService
  3. Moduler lastet inn ved behov og funksjonsbrytere
  4. Utvidelsespunkter med Module Reference API
← Tilbake til NestJS-API-er for virksomhetsbackend