Módulos
Un módulo reúne los controladores y providers de una funcionalidad. La app es un árbol de módulos: el módulo raíz, el que pasas a createApp, importa a los demás, y cada uno puede importar otros.
En la primera app ya escribiste dos: BooksModule y AppModule. Esta página explica qué pasa entre ellos.
Las opciones de @Module
Section titled “Las opciones de @Module”| Opción | Para qué sirve |
|---|---|
imports |
Módulos cuyos providers exportados quieres usar. |
controllers |
Controladores del módulo. viga registra sus rutas. |
providers |
Clases y valores que el módulo crea y puede inyectar. |
exports |
Providers del módulo que otros módulos pueden usar al importarlo. |
global |
Hace que sus exports estén disponibles en toda la app. Lo ves más abajo. |
Todas son opcionales. Un módulo sin opciones, @Module({}), es válido aunque no aporta nada.
Cada módulo es privado por defecto
Section titled “Cada módulo es privado por defecto”Cada módulo tiene su propio contenedor. Un provider declarado en providers solo lo pueden inyectar las clases de ese mismo módulo, a menos que lo exportes.
Supón que agregas autores a la app y quieres que BooksService use AuthorsService:
import { Module } from 'viga';import { AuthorsService } from './authors.service.ts';
@Module({ providers: [AuthorsService],})export class AuthorsModule {}import { Module } from 'viga';import { AuthorsModule } from '../authors/authors.module.ts';import { BooksController } from './books.controller.ts';import { BooksService } from './books.service.ts';
@Module({ imports: [AuthorsModule], controllers: [BooksController], providers: [BooksService],})export class BooksModule {}Aunque BooksModule importa AuthorsModule, la app no arranca:
[DI] BooksModule cannot resolve AuthorsService: it is missing from providers or from the exports of an imported moduleAuthorsService existe, pero es privado de AuthorsModule. Importar un módulo solo da acceso a lo que exporta.
Exporta lo que otros necesitan
Section titled “Exporta lo que otros necesitan”Agrega AuthorsService a exports:
import { Module } from 'viga';import { AuthorsService } from './authors.service.ts';
@Module({ providers: [AuthorsService], exports: [AuthorsService],})export class AuthorsModule {}Ahora BooksService puede pedirlo con inject(AuthorsService). Lo que no exportes sigue siendo un detalle interno del módulo: puedes cambiarlo sin romper a nadie.
Solo exportas providers que el módulo declara o que recibe de sus imports. Los controladores no se exportan: sus rutas se registran igual, sin importar quién importe el módulo.
Una sola instancia por provider
Section titled “Una sola instancia por provider”viga carga cada módulo una sola vez, aunque lo importen varios. Si BooksModule y ReviewsModule importan AuthorsModule, los dos reciben la misma instancia de AuthorsService.
Dentro de un módulo, cada provider se crea la primera vez que alguien lo pide y después se reutiliza. Por eso un provider puede guardar estado, como la lista de libros en memoria de la primera app.
Reexporta módulos
Section titled “Reexporta módulos”Un módulo puede exportar un módulo que importa. Así, quien lo importe recibe también los exports de ese otro módulo:
import { Module } from 'viga';import { AuthorsModule } from '../authors/authors.module.ts';import { PublishersModule } from '../publishers/publishers.module.ts';
@Module({ imports: [AuthorsModule, PublishersModule], exports: [AuthorsModule, PublishersModule],})export class SharedModule {}Importar SharedModule equivale a importar AuthorsModule y PublishersModule. Sirve para agrupar módulos que casi siempre se usan juntos.
Módulos globales
Section titled “Módulos globales”Algunos providers los necesita casi toda la app, como la configuración. Importar su módulo en cada sitio sería repetitivo; con global: true, sus exports están disponibles en todos los módulos sin importarlo:
import { Module } from 'viga';import { Clock } from './clock.ts';
@Module({ global: true, providers: [Clock], exports: [Clock],})export class ClockModule {}Un módulo global se importa una vez, en el módulo raíz:
import { Module } from 'viga';import { BooksModule } from './books/books.module.ts';import { ClockModule } from './clock/clock.module.ts';
@Module({ imports: [ClockModule, BooksModule] })export class AppModule {}Si lo importas desde otro módulo, viga no arranca y te dice dónde moverlo:
[Module] ClockModule is global and is imported from BooksModule, but not from the root module; move it to the imports of AppModuleEsta regla hace que todos los módulos globales se vean en un solo archivo. ConfigModule.forRoot(), de viga/config, es un módulo global y se importa así.
Dónde busca viga un provider
Section titled “Dónde busca viga un provider”Cuando una clase pide un provider con inject(), viga lo busca en este orden y usa el primero que encuentra:
- Los
providersdel propio módulo. - Los
exportsde los módulos que importa, incluidos los que estos reexportan. - Los
exportsde los módulos globales.
Si no aparece en ninguno, la app no arranca y el error nombra el módulo y el provider que falta.
Errores al cargar los módulos
Section titled “Errores al cargar los módulos”viga revisa el árbol de módulos al arrancar y falla antes de abrir el puerto:
- Importación circular. Si
BooksModuleimportaAuthorsModuleyAuthorsModuleimportaBooksModule, el error muestra la cadena desde el módulo raíz:[Module] Circular import: AppModule -> BooksModule -> AuthorsModule -> BooksModule. Suele indicar que hay un provider que debería vivir en un tercer módulo que los dos importen. - Clase sin
@Module(). Si pones enimportsuna clase que no es un módulo:[Module] AuthorsService must be decorated with @Module().