Estructura de un proyecto en Ionic y descripción de ficheros (II)

Manuel García29-Oct, 2019

Primera parte del artículo: Estructura de un proyecto en Ionic y descripción de ficheros (I)

Estructura personalizada en Ionic y comparación con estructura base

Una vez visto en el apartado anterior algunos de los archivos más importantes, en esta parte se muestra una estructura de proyecto con un desarrollo más avanzado, enfocada a un caso o casos prácticos reales.

Para ilustrar mejor las diferencias, se exponen dos imágenes: la imagen de la izquierda, que hace referencia a la estructura básica y a la derecha, la estructura personalizada propuesta.

Directorio src/app

Las principales diferencias residen en los directorios. En la estructura base las páginas están siempre al mismo nivel y no hay una organización enfocada a varios niveles. Ionic deja libertad organizativa para que sea el propio desarrollador el que marque su propia estructura.

Hay varias cosas a analizar en la estructura de la derecha. Por un lado, los directorios “core” y “shared”, heredados de una de las estructuras personalizadas que plantea Angular en su web oficial y, por otro, los directorios “private” y “public”, carpetas personalizadas y que define la estructura de páginas del proyecto en cuestión.

Explicando el contenido a destacar de la carpeta principal “app”:

app.module.ts: Este archivo, ya explicado brevemente en el apartado anterior, carga módulos y componentes para todas las páginas, de forma que actúe como “caché”. Es decir, cargará módulos que requieren un uso más bien centralizado y solo se cargará una vez, al iniciar la aplicación, ahorrando velocidad de carga y aprovechando la potencia de lazy loading que permite Angular.

core: Este directorio contendrá la definición de entidades, servicios, componentes, interceptores, etc. Es decir, todo el código destinado a ofrecer la lógica de dominio de la aplicación. De esta forma, todas las páginas podrán tener acceso desde un único punto.

Cualquier módulo de la aplicación, es decir, cualquier página contenida en “private” y “public”, podrá hacer uso de cualquier elemento de “core”, simplemente importando en “app.module.ts” el módulo “core.module.ts”. Esto quiere decir que el módulo solo se cargará una vez al iniciar la aplicación y no será necesario cargarlo en ningún otro lugar.

shared: Este directorio, también heredado de la estructura recomendada por Angular, está destinado a contener aquellos componentes, directivas, pipes y/o módulos de uso compartido. Lo ideal al crear esta carpeta es crear un módulo “shared.module.ts” que servirá de exportador de módulos al resto de la aplicación. A diferencia de la carpeta “core”, el módulo “shared” será importado por cualquier otro módulo o página que requiera hacer uso de elementos declarados (exportados) en el módulo “shared.module.ts”. Es decir, el módulo “shared” no se incluye en el módulo principal de la aplicación “app.module.ts”.

En la captura del proyecto de ejemplo, existe un archivo “validator.ts”, que incluye funciones públicas destinadas a la validación de formularios. Es común también tener un archivo “globals.ts” o “utils.ts” donde guardar funciones públicas que se exportan para que el resto de la aplicación pueda hacer uso de ellas.

La anterior captura es un ejemplo de los módulos que exporta y los módulos “providers”. Aquí se declaran, entre otros, los módulos derivados de cualquier paquete instalado para tener tan solo un punto de declaración. Por ejemplo, se indica que el proyecto declara “providers” como el módulo Camera o CallNumber. Así, si una o varias de las páginas hacen uso en algún momento de la cámara o de una llamada de teléfono, tan solo tendrá que importar el módulo “shared” la página concreta. Luego ya el lazy loading hará su función únicamente cargando el módulo concreto según el uso que se le dé en la página.

Diferencias entre core y shared: Una de las principales dudas que pueden surgir es acerca de dónde declarar o introducir un nuevo archivo (componente, servicio, módulo, etc.). Teniendo claro las principales diferencias de importación y uso de elementos de los diferentes módulos, es más sencillo entender cuál será la mejor forma de separar y asociar a un módulo u otro el elemento a crear.

  • En la carpeta “core” deben ir destinados los elementos de lógica y comunes a prácticamente todas las páginas de la aplicación. Modelos, servicios, componentes que necesiten lógica… elementos destinados a ofrecer o nutrir a la lógica de cada página, funcionalidad nueva.
  • En la carpeta “shared” deben ir elementos tales como directivas, archivos de utilidades, pipes, componentes visuales no muy complejos (si son complejos mejor que vayan a “core” ya que si no se estarían solapando ambos módulos).

private y public: Estos dos directorios ayudan en la organización de la estructura de páginas. La idea es derivar a uno u otro directorio según si la página es de visualización pública o privada (necesario login).

Cada uno de los directorios tendrá un archivo de módulo (public|private.module.ts) y un archivo de rutas (public|private-routing.module.ts). Los módulos, en este caso, sirven para especificar cuál es el archivo de rutas asociado y también importan el módulo “shared” para que los elementos exportados por este módulo estén disponibles en todas las páginas “hijas” tanto de “public” como de “private”.

El módulo de rutas, define, a partir del módulo contenedor (public o private), todas las rutas y su organización. Ejemplo del enrutado del módulo “public”:

Este planteamiento nos ayuda a distinguir más rápidamente qué página estará protegida. Si la aplicación acaba teniendo una versión web, bien sea una PWA o una web pura, esta estructura de directorios en base a rutas puede ser una gran opción.

Directorio src/theme

En el anterior apartado ya se comentó que en este directorio se encuentran los archivos de estilos globales, solo que en la estructura personalizada que se plantea hay algunos archivos más.

La intención de la carpeta “partials” es contener archivos de estilos que sean reutilizables entre una o más secciones, sean páginas, componentes, etc. Su formato de nombre es: “_nombre.scss” y será importado por las páginas o componentes que necesiten el “partial” concreto.

Los “mixins” son funciones en SASS que sirven para reutilizar algunas aplicaciones de estilos mediante propiedades o selectores. El archivo “mixins.scss” tiene como objetivo almacenar estas funciones. Si un archivo de estilos de una página o componente necesita invocar (incluir) un mixin concreto, realizará una importación de este archivo “mixins.scss” y después incluirá (include) el mixin concreto a utilizar.

Es bueno tener esta separación para favorecer la reutilización de estilos una vez el proyecto va creciendo.

config.xml

Este archivo no hace referencia a ninguna estructura personalizada. Es un archivo ubicado en la raíz del proyecto y se crea de forma automática al construir la aplicación para un dispositivo nativo, Android o iOS. Viene a ser un alias del archivo “package.json” de Node pero con la diferencia de que es el archivo principal de una aplicación de Cordova. Se almacena el identificador de la aplicación, la descripción, la versión actual de la aplicación y puede contener características por plataforma. En la captura siguiente un ejemplo de propiedades para la plataforma de Android. Propiedades como el acceso a las imágenes o iconos principales, paquetes a utilizar con su clave de acceso a un API externa (Google Maps API), etc.

Variaciones y limitaciones

La estructura personalizada que se plantea en este apartado tiene ventajas e inconvenientes según el tipo de proyecto. A continuación se enumeran algunas limitaciones y se plantea otra variación de la estructura.

  • Limitación: Nueva página donde no quede claro si es privada o pública. A veces puede darse el caso de que la página nueva que se quiera hacer no quede claro si crearla en “private” o en “public”, ya que puede tener propiedades o estilos diferentes si es de un tipo u otro. En este caso, lo mejor será guardarla en el directorio privado para detectar desde un primer vistazo en la navegación por carpetas que la página contendrá contenido privado. Ya en el sistema de rutas, crear una referencia en el módulo “public” y otra referencia en el módulo “private”. Esto es, para evitar que las rutas protegidas de “private” no actúen bloqueando el acceso cuando se requiera acceso público a la página en cuestión.
  • Estructura sin carpeta “shared”: Si el proyecto no va a ser muy complejo, se puede optar por prescindir del directorio “shared”. Los módulos que exporta para facilitar el reutilizado pueden pasar a referenciarse en el módulo principal “app”. Si existen archivos globales como un archivo de funciones, validadores de formulario, “utils”, etc. pueden crearse en el directorio “src/app” e ignorar así el directorio “shared” por completo.
  • Estructura orientada a funcionalidades (features): Existe otra alternativa de estructura personalizada, y no es más que orientar la estructura de las páginas/componentes a las funcionalidades. Por ejemplo, si existe una funcionalidad o sección que sea “usuarios”, se creará dicho directorio y en él se almacenarán todos los elementos, incluyendo un módulo con el mismo nombre, para trabajar con todos sus elementos tales como: páginas asociadas, componentes, modelos, servicios, etc. Esta estructura tiene como ventaja que en un solo módulo (directorio) se encuentra todo lo necesario pero tiene como limitación el caso de que existan funcionalidades donde actúen varios elementos (usuarios con facturas, usuarios con servicios, etc.) y ahí sea más difícil estructurar y añadir según qué página hija, componente, o elemento.

Conclusiones

La estructura personalizada que se plantea sirve para organizar y visualizar mejor las páginas que se creen en cualquier aplicación. Es sencilla de aplicar y mejora bastante la navegación entre directorios del proyecto.

No existe estructura perfecta y siempre hay que adecuar cada estructura al proyecto concreto que se vaya a realizar. Dicho esto, esta estructura está recomendada ya sea un proyecto sencillo o complejo, ya que separa bastante bien todos los elementos necesarios.

Si la aplicación a crear va a contener muchas páginas, siempre será recomendable hacer una organización que junte varias páginas en un solo directorio. No se recomienda crear todas las páginas en el mismo nivel si el proyecto crece ya que si no luego será difícil detectar o hacer algún cambio que se necesite.

Manuel García

Desarrollador full stack web y móvil. En evolución constante.