3.0 / 5
Actualmente en la documentación oficial de Angular hay 12 páginas largas para explicar cómo funcionan los NgModules, incluidas las preguntas frecuentes. Pero después de leer todo esto, puede ser que aun quedemos confundidos. Preguntas básicas como “¿dónde es un buen lugar para guardar un servicio?” No tienen una respuesta clara, incluso hay sugerencias a veces contradictorias.
Asà que vamos a repensar todo e implementar una arquitectura decente para aplicaciones Angular , con estos objetivos en mente:
El propósito de un NgModule es solo agrupar componentes y / o servicios que se pertenecen . Ni más o menos.
Entonces puede comparar eso con un paquete Java o un espacio de nombres PHP / C #.
La única pregunta es: ¿cómo eliges agrupar cosas?
Hay 3 tipos principales de NgModules que puedes hacer:
Los modulos de componente se usaran siempre (de lo contrario, su aplicación está vacÃa). Los otros 2 tipos de módulos son opcionales, pero llegarán pronto si desea reutilizar y optimizar su código.
Los módulos de páginas son módulos con enrutamiento . Están aquà para separar y organizar las diferentes áreas de su aplicación . Se cargan solo una vez , ya sea en el AppModule o mediante la carga diferida .
Por ejemplo, podrÃa tener un AccountModule para las páginas de registro, inicio de sesión y cierre de sesión; luego, un HeroesModule para la lista de héroes y páginas de detalles de héroes; y asÃ.
Estos módulos contienen 3 cosas:
Para mostrar datos en una página, primero necesita datos. Aquà es donde intervienen los servicios.
Pronto, varias páginas necesitarán el mismo servicio. Por lo tanto es recomendable agregar los servicios en el directorio Shared .
Pero asegúrese de que sus servicios para las páginas sean especÃficos del módulo , ya que si opta por  lazy-loading , solo estarán disponibles en este módulo particular (lo cual es bueno), y no en otra parte de la aplicación.
Retomemos un AccountModule como ejemplo. El servicio de cuenta solo debe administrar la comunicación con la API (que dice “sÔ o “no” en función de las credenciales del usuario). El estado de conexión del usuario no se debe almacenar aquÃ, ya que puede no estar disponible en otra parte de la aplicación. Será administrado por un módulo de servicios globales (ver a continuación).
Un componente de página simplemente inyecta el servicio y lo usa para obtener los datos.
Se podrÃa mostrar los datos directamente en el componente de la plantilla pero deberÃa no : los datos deben ser transferidos a otro componente a través de un atributo.
Cada componente de página está asociado a una ruta .
Un componente de presentación simplemente recupera los datos transferidos con el decorador de entrada y lo muestra en la plantilla.
@Component({ selector: 'app-presentation', template: `<h1>{{data.title}}</h1>` }) export class PresentationComponent { @Input() data: SomeData; }
En un nivel teórico, no. Pero si vienes del mundo de back-end y te ayuda en un nivel práctico, puedes compararlo:
Incluso no es exactamente el mismo concepto, el objetivo es el mismo: separación de preocupaciones . Y ¿Por qué es esto importante?
Ejemplo de un módulo de páginas:
Los módulos de servicios globales son módulos con servicios que necesita a través de toda la aplicación . Como los servicios tienen generalmente un alcance global , estos módulos se cargan solo una vez en el AppModule, y luego se puede acceder a los servicios en cualquier lugar (incluso en los módulos con carga diferida).
Ciertamente usa al menos uno: el módulo HttpClient . Y pronto necesitarás la tuya. Un caso muy común es un AuthModule para almacenar el estado de conexión del usuario (ya que esta información es necesaria en todas partes en la aplicación) y guardar el token.
Nota: desde Angular 6, ya no necesita un módulo para los servicios , ya que ellos mismos se proveen automáticamente. Pero no cambia la arquitectura descrita aquÃ.
Los módulos de servicios globales son reutilizables a través de diferentes proyectos si se cuida de no tener una dependencia especÃfica en ellos (sin UI o código especÃfico de la aplicación), y si se separan cada una en diferentes módulos ( no coloque cada servicio en un solo módulo global grande) )
Como dicho módulo se usará desde el exterior, debe hacer un punto de entrada , donde puede exportar el NgModule, los servicios y tal vez las interfaces y los tokens de inyección.
No es necesario . La documentación sugiere hacer un CoreModule para servicios globales. Seguramente puede agruparlos en un directorio / core / , pero como se mencionó anteriormente, asegúrese de separar primero cada caracterÃstica . Usted debe no poner todos los servicios globales en un solo CoreModule, de lo contrario no será capaz de volver a utilizar sólo una caracterÃstica en otro proyecto.
Ejemplo de un módulo de servicios globales:
De nuevo, el módulo no es necesario desde Angular 6.
Los módulos de componentes re utilizables son módulos de componentes de UI que le gustarÃa reutilizar en diferentes proyectos. Como los componentes tienen un alcance local , estos módulos se importan en los módulos de cada página donde los necesita.
Ciertamente usa uno, como Material , NgBootstrap o PrimeNg . Tú también puedes hacer lo tuyo.
Los componentes de interfaz de usuario son componentes de presentación puros . Por lo tanto, funcionan exactamente igual que en los módulos de páginas (ver arriba): los datos deben venir del decorador de entrada (y a veces de <ng-content> en casos avanzados).
Usted debe no confiar en un servicio, ya que los servicios son a menudo especÃficos para una aplicación en particular. ¿Por qué? Al menos debido a la API URL. Proporcionar los datos será el papel del componente de páginas. El componente UI solo recupera datos pasados ​​por otra persona.
Como los componentes están en el ámbito local , no olvide exportarlos en el NgModule. Solo necesita exportar los públicos , los sub componentes internos pueden mantenerse privados.
Un módulo UI también puede ser sobre directivas o tuberÃas. Igual que los componentes: necesitan ser exportados si son públicos.
Los servicios dentro de los módulos de UI pueden ser relevantes para la manipulación de datos si no contienen nada especÃfico. Pero luego, asegúrese de proporcionarlos en el componente , para que tengan un alcance local / privado, y ciertamente no en el NgModule.
Pero, ¿qué sucede si su módulo de UI también necesita proporcionar servicios públicos en relación con el componente? Se debe evitar tanto como sea posible, pero es relevante en algunos casos.
A continuación, proporcionará los servicios públicos en el NgModule. Pero como el módulo se cargará varias veces debido al alcance de los componentes, causará un problema para los servicios.
Luego necesita un código adicional para cada servicio público para evitar que se carguen varias veces . SerÃa demasiado largo para explicarlo aquÃ, pero es una mejor práctica (hecho en Material, por ejemplo). Simplemente reemplace SomeService por el nombre de su clase:
export function SOME_SERVICE_FACTORY(parentService: SomeService) { return parentService || new SomeService(); } @NgModule({ providers: [{ provide: SomeService, deps: [[new Optional(), new SkipSelf(), SomeService]], useFactory: SOME_SERVICE_FACTORY }] }) export class UiModule {}
Los módulos de los componentes de la interfaz de usuario son re-utilizables a través de diferentes proyectos. Como se usará desde el exterior, debe hacer un punto de entrada , donde puede exportar el NgModule, los componentes públicos / exportados (y tal vez directivas, tuberÃas, servicios públicos , interfaces y tokens de inyección).
export { SomeUiComponent } from './some-ui/some-ui.component'; export { UiModule } from './ui.module';
No se . La documentación sugiere hacer un SharedModule, para factorizar todos los módulos de componentes dentro de un módulo. Pero iré en contra de la documentación de este.
El problema es que cada módulo en el que importa el SharedModule se vuelve especÃfico para su aplicación y luego no será reutilizable en otro proyecto.
Es normal tener que importar dependencias cada vez que los necesite. Y con las herramientas actuales, como las importaciones automáticas en VS Code , ya no es una carga.
Pero seguramente puede agrupar sus módulos de componentes dentro de un directorio / ui / (no lo llame / compartido /, será confuso con los servicios que también se comparten).
Ejemplo de un módulo de componentes de UI reutilizables:
@NgModule({ imports: [CommonModule], declarations: [PublicComponent, PrivateComponent], exports: [PublicComponent] }) export class UiModule {}
Si sigues esos pasos:
Aquà hay un ejemplo de una arquitectura del mundo real:
app/ |- app.module.ts |- app-routing.module.ts |- core/ |- auth/ |- auth.module.ts (optional since Angular 6) |- auth.service.ts |- index.ts |- othermoduleofglobalservice/ |- ui/ |- carousel/ |- carousel.module.ts |- index.ts |- carousel/ |- carousel.component.ts |- carousel.component.css |- othermoduleofreusablecomponents/ |- heroes/ |- heroes.module.ts |- heroes-routing.module.ts |- shared/ |- heroes.service.ts |- hero.ts |- pages/ |- heroes/ |- heroes.component.ts |- heroes.component.css |- hero/ |- hero.component.ts |- hero.component.css |- components/ |- heroes-list/ |- heroes-list.component.ts |- heroes-list.component.css |- hero-details/ |- hero-details.component.ts |- hero-details.component.css |- othermoduleofpages/
El objetivo de este post es también confrontar esta arquitectura con la comunidad, es decir, usted que está leyendo. Entonces, si me perdà algunos casos de uso, siéntete libre de comentar.
Esta arquitectura base la pude aprender del siguiente articulo, es muy bueno, y si siguen sus otros post, podrán aprender mas sobre las base de angular a profundidad.
Fuente: Architecture in Angular projects – Cyrille Tuzi – Medium