Reorganizando AngularDex: Módulos y Enrutamiento
AngularDex (V)
Si has ido siguiendo al pie de la letra las clases anteriores, tendrás la siguiente estructura de carpetas:
Como te puedes dar cuenta, este esquema no es precisamente bonito… si continuamos así vamos a acabar con una aplicación difícil de mantener y extremadamente ineficiente. Para mejorar la escalabilidad y el rendimiento de AngularDex debemos empezar a pensar en Módulos e ir agrupando la lógica (componentes, pipes, directivas…) en estos. Además, vamos a crear una estructura de carpetas que personalmente encuentro bastante limpio, lo he podido probar en aplicaciones de todo tipo y siempre he recibido un feedback bastante positivo, así que ¡Vamos manos a la obra!
Reestructurando las carpetas
A mí me gusta utilizar el modelo COMOSH. Con este modelo vamos a tener solamente 3 carpetas hijas de app, las cuales serían:
- core: Esta carpeta contendrá el CoreModule. La idea de este módulo es contener aquellos elementos que solo se pueden instanciar una vez a lo largo de toda aplicación, es decir, solo se cargan una vez. Un buen ejemplo sería un servicio de Login, así como los componentes estáticos como Header, Footer o Navbar. Es recomendable crear un “Module Import Guard” para prevenir reimportaciones.
- modules: En este directorio se encontrarán todos los módulos o “features” de la aplicación, es decir, agruparemos por cada módulo los componentes, servicios, modelos… que tengan un fin común.
- shared: Dentro de esta carpeta tendrás todos aquellos elementos que se puede re-aprovechar a lo largo de la aplicación. Estos elementos deben estar aislados del resto, es decir, las únicas dependencias deberían ser las del propio framework o de librerías de externas.
Una vez explicado esto podemos proceder a la reestructuración, quedaría tal que así:
Creando nuevos módulos
Perfecto ya tenemos el esqueleto, la estructura de carpetas, pero ahora falta añadir los nuevos módulos, recuerda que hasta ahora el único módulo existente es el AppModule, ahora necesitamos crear el CoreModule, PokemonModule y SharedModule:
CoreModule
Actualmente, este módulo se encuentra vacío dado que aún no tenemos componentes estáticos (Header o Footer), pero lo dejamos preparado para cuando necesitemos este tipo de componentes.
ng g m core
SharedModule
De momento, nuestro único elemento reutilizable es PadStartPipe, así que debemos declararlo en el módulo y exportarlo para que otros puedan utilizarlo.
ng g m shared
Modules > PokemonModule
Este será el módulo que contendrá todo lo relacionado los Pokémon, como PokemonCard, PokemonService o PokemonTypeDirective. Aquí principalmente tendrá todos aquellos elementos que el único contexto válido es lo relacionado con los Pokémon. Un aspecto importante es que como este será un Módulo que puede contener rutas, necesitaremos crear dicho módulo con el parámetro — routing
ng g m modules/pokemon --routing
También vamos a aprovechar a optimizar nuestro PokemonService para que en lugar de ser cargado en la inicialización de la aplicación con AppModule (servicio “root”) sea cargado solamente cuando sea necesario, es decir, con PokemonModule. Para ello es tan fácil como informar a null la propiedad providedIn de los metadatos del decorador Injectable del servicio:
OJO: al hacer esto nos vemos obligados a que en los módulos que inyecte este servicio se informe como “provider” tal como está en la captura del módulo.
AppModule
Ahora necesitamos mover la lógica y la maquetación del AppComponent, como de momento lo único que teníamos codificado era la renderización del PokemonCard y la obtención de datos, es tan simple como crear un componente “PokemonPage” y copiar-pegarlo todo (scss, ts y html) aquí.
ng g c modules/pokemon/components/pokemon-page
Implementando rutas
En nuestro pokemon-routing.module.ts añadimos las rutas que nos interesa, de momento solo queremos mostrar el PokemonPage (recuerda que es lo que anteriormente era AppComponent)
Ahora hacemos algo parecido en AppRoutingModule, en este caso lo que debemos hacer es, en primer lugar, que redirija a ‘“/pokemon” cuando accedemos a la raíz de la aplicación. Posteriormente, definimos la ruta “pokemon” la cual se encargará de cargar PokemonModule (recuerda que estamos utilizando lazy loading) el cual contiene las rutas definidas anteriormente.
¡No olvides añadir
<router-outlet></router-outlet>
en tu app.component.ts!
Controlando urls no desarrolladas
Para ello vamos a crear el componente PageNotFound, al ser un componente estático y común en toda la aplicación encaja perfectamente en nuestro CoreModule, por lo que aparte de crearlo en la carpeta correspondiente, también necesitaremos exportarlo.
ng g c core/components/page-not-found
Y simplemente vamos a hacer que muestre un 404 Page Not Found (te reto a hacerlo un poco más bonito 😜)
Por último, actualizamos nuestro archivo de rutas:
Si ahora intentamos acceder a nuestro querido localhost:4200/ nos daremos cuenta de que nos redirige a /pokemon y nos muestra el estado de Pokémon justo como lo hacía antes
Mientras que si intentamos a acceder a cualquier otra ruta: