Guía de desarrollo de soluciones web-microfrontend

Información general

Herramientas de desarrollo

Entornos de desarrollo

El entorno de desarrollo integrado es esencial para los desarrolladores de software. La elección de un IDE (Integrated Development Environment) adecuado y la configuración de los plugins y herramientas correctas puede mejorar significativamente la eficiencia y la calidad del desarrollo.  

Desde la Agencia no se impone ninguno en particular, entendiendo que es una cuestión de preferencias de cada desarrollador. Visual Studio Code es la opción más popular para el desarrollo de aplicaciones Angular.

Visual Studio Code

Visual Studio Code (VS Code) es un editor de código fuente ligero pero potente ampliamente adoptado por los desarrolladores Angular. Con su enfoque modular, VS Code permite a los usuarios personalizar su entorno de desarrollo a través de extensión de plugins, que abarcan desde soporte para lenguajes de programación hasta herramientas de depuración y control de versiones. 

VS Code ofrece características robustas como autocompletado inteligente, integración con Git y soporte para depuración, con un completo soporte de Angular. Además, Visual Studio Code es de código abierto, bajo la licencia MIT, lo que lo convierte en una opción accesible para desarrolladores individuales y equipos que buscan una herramienta flexible y extensible.

Plugin recomendados

Para el desarrollo con Angular: 

node y npm

Para desarrollar una aplicación SPA es necesario contar con Node.js, un entorno de ejecución que permite usar JavaScript fuera del navegador, y con npm (Node Package Manager), el gestor de paquetes oficial de Node, que se utiliza para manejar las dependencias en el entorno local de desarrollo.   

Se pueden descargar en https://nodejs.org 

Para verificar la correcta instalación desde un terminal: 

node -v
npm -v

Es necesaria una versión de node igual o superior a node20 (20.19.4 es la versión LTS).

Navegador Web

Se puede utilizar cualquier navegador moderno (Chrome, Firefox, Edge, Safari, ...) para comprobar el funcionamiento de la aplicación en desarrollo. 

Para realizar pruebas y tareas de depuración, se recomienda emplear el navegador Google Chrome por su sencilla configuración para su utilización con Karma (el test runner* que utiliza Angular por defecto). Su utilización viene preconfigurada por parte de Karma, no siendo necesaria ninguna configuración adicional. 

*Test runner: herramienta que se encarga de ejecutar automáticamente las pruebas de software 

Desarrollo de la aplicación

Diseño

Utilizar como base la arquitectura de referencia Microfrontend y las normas; realizando un diseño apropiado que tenga en cuenta:

  • Estructura de la aplicación: Consultar la arquitectura de referencia para obtener más información sobre los componentes que pueden ser utilizados en la construcción de la aplicación.
  • Patrones de arquitectura y diseño: De igual modo en la arquitectura de referencia se puede consultar la información sobre los diferentes patrones que pueden ser aplicados y escoger los que mejor se adapten a las necesidades de la aplicación.

Construcción

Elección del framework de desarrollo

Implementación de la arquitectura Shell + Microfrontends

Existen diversas opciones para para implementar una aplicación con una Shell + Microfrontends. Este enfoque divide la interfaz en microaplicaciones autónomas, mientras la Shell orquesta navegación, comunicación y experiencia común. El resultado es mayor autonomía de equipos, despliegues independientes y la posibilidad de convivir con distintos frameworks sin sacrificar una UX coherente.

El ecosistema ofrece diferentes piezas complementarias para orquestación y enrutado, para cargar Microfrontends y compartir dependencias en tiempo de ejecución, WebComponents, etc. La elección suele venir dada por restricciones organizativas (gobernanza, usabilidad, accesibilidad, seguridad), stack existente, requisitos de aislamiento y objetivos de rendimiento.

A continuación, se presentan diferentes opciones:

  • single-spa: agnóstico al framework (React, Vue, Angular, etc.), ciclo de vida claro por microapp, enrutamiento por zonas, probado en producción durante años, compatible con SystemJS/Import Maps. Ideal para shells que montan/desmontan MFs heterogéneos.
  • Webpack 5 Module Federation: compartir dependencias en tiempo de ejecución (evita duplicados), “host/remotes” para que la shell consuma MFs independientes, versionado/estrategias de “shared” finas, despliegues independientes sin recompilar todo el shell.

Desde la Agencia se ha seleccionado Module Federation con el objetivo de establecer un framework base para fomentar la reutilización y publicación de distintos componentes para generar sinergias entre proyectos y aplicaciones.

Su elección se ha basado en:

  • Dependencias compartidas en tiempo de ejecución entre microfrontends. 

Despliegues realmente independientes: los remotes pueden publicarse y actualizarse sin necesidad de redesplegar el contenedor. Esto facilita rollbacks rápidos y evolución gradual de cada microfrontend. 

Opciones de Frameworks y Herramientas para Module Federation

Al implementar un enfoque de Microfrontends con Shell + Module Federation, existen varias opciones de frameworks y librerías que facilitan la integración entre aplicaciones:

  • Angular + Module Federation: Angular CLI ofrece soporte nativo para Module Federation a través del Angular Architects Module Federation Plugin. Configuración simplificada, integración fluida con Angular Router, soporte oficial y comunidad activa.
  • React + Module Federation: React junto con @module-federation/nextjs-mf (para Next.js) o configuración personalizada de Webpack. Ecosistema maduro, soporte para aplicaciones SPA y SSR, integración sencilla con React Router.
  • Vue.js + Module Federation: Configuración directa en Vue CLI o Vite + Webpack, apoyándose en librerías como vite-plugin-federation. Ligero y flexible, buen soporte para proyectos nuevos con Vite.
  • Vanilla JS + Webpack Module Federation: Uso directo de Webpack 5 con Module Federation sin framework específico. Máxima flexibilidad, control fino sobre la configuración, framework-agnostic.

Desde la Agencia se proporciona un framework propio basado en Angular + Module Federation para facilitar la homogeneidad y reutilización en el desarrollo de nuevas aplicaciones, componentes Shell o componentes microfrontends.

Implementación utilizando ada-fw-webapps como framework de desarrollo

Es el framework proporcionado por la Agencia. Está basado en Native Federation de Angular, que es una implementación “browser-native” del mismo modelo que Module Federation, pero apoyada en ESM e Import Maps. En el contexto de Angular moderno —Angular CLI con esbuild/Vite— permite que la Shell resuelva Microfrontends remotos y comparta dependencias en tiempo de ejecución manteniendo una sola instancia de Angular cuando es posible.

Requisitos

Instalar la versión de Angular definida

Revisar la versión exacta de Angular; para descargar e instalar Angular CLI:   

npm install –g @angular/cli@19.2.15

Instalar Yeoman CLI 

Yeoman es una herramienta que ayuda a iniciar proyectos de software de forma rápida y organizada. Permite generar la estructura básica de una aplicación a partir de plantillas prediseñadas (llamadas generadores), lo que ahorra tiempo y asegura buenas prácticas desde el inicio del desarrollo. 

Para su utilización, abrir una terminal e instalar Yeoman globalmente:

npm install -g yo

Para verificar la instalación:

yo --version

Se debería ver la versión de Yeoman instalada. 

Descargar e instalar en el entorno local el archivo con el proyecto del generador 

  1. Descargar el fichero .tgz con la última versión desde el repositorio de binarios de la Junta (es necesario estar conectado a la VPN): Repositorio 
  2. Instalar el generador globalmente en el entorno local:
npm install -g ./generator-ada-fwk-webapps-1.0.2.tgz
  1. Verificar la instalación; ada-fwk-webapps debe aparecer en la lista:
yo --generators
Generación de la solución

Ejecución del arquetipo

El primer paso es la ejecución del arquetipo para obtener la estructura de la aplicación de microfontends. Para ello es necesario verificar que se dispone de conectividad con Artifactory por lo que será necesario estar conectado a la VPN si el equipo local está fuera de la red de la Junta.

En primer lugar, crear un nuevo directorio para el proyecto:

mkdir mi-proyecto-ada
cd mi-proyecto-ada

Ejecutar el generador Yeoman:

yo ada-fwk-webapps
Captura pantalla ada-fwk-webapps
  • Seleccionar MicroFrontend (MFE)
  • Dar nombre al proyecto
  • Seleccionar Shell App y MFE App si es la primera vez y queremos generar el proyecto completo o Solo MFE App si ya tenemos la Shell y queremos un microfrontend independiente.
  • El proyecto se genera automáticamente y se instalan todas las dependencias.
Estructura del Proyecto

La estructura del proyecto sigue un diseño modular basado en Arquitectura Hexagonal, separando claramente las diferentes responsabilidades del código. Este enfoque permite crear aplicaciones escalables, mantenibles y fáciles de extender.

Estructura General

Estructura general de la shell:

src/
├── app/
│   ├── application/        	# Casos de uso y servicios de aplicación
│   ├── domain/             	# Modelos de dominio y contratos (interfaces)
│   ├── infrastructure/     	# Adaptadores como API, servicios HTTP, etc.
│   ├── presentation/       	# Componentes standalone (UI)
│   │   ├── components/     # Componentes reutilizables
│   │   ├── pages/          	# Páginas de la aplicación (rutas principales)
│   ├── state/              	# Configuración de NGRX (estado global)
│   │   ├── actions/        	# Acciones NGRX
│   │   ├── effects/       	# Efectos NGRX
│   │   ├── reducers/       	# Reducers NGRX
│   │   ├── selectors/        	# Selectores NGRX
│   │   └── global.store.ts	# Store global manejado por la shell
│   ├── app.routes.ts       	# Configuración de rutas
│   ├── app.config.ts       	# Configuración principal de la aplicación
│   ├── app.component.ts  # Componente principal
│   ├── app.component.html  # Template principal
│   └── app.component.scss  # Estilos principales
├── assets/                 	# Recursos estáticos (imágenes, fuentes, etc.)
│   ├── federation.manifest.ts       # URLs de los mfes
├── environments/           	# Configuración para diferentes entornos (desarrollo/producción)
├── bootstrap.ts           	# Configuracion de aranque de la aplicación
despliegue/		# configuración de despliegue por entorno
ci.json			# configuración para CI
federation.config.js		# Configuración de native federation

Estructura general de un mfe:

src/
├── app/
│   ├── application/        # Casos de uso y servicios de aplicación
│   ├── domain/             # Modelos de dominio y contratos (interfaces)
│   ├── infrastructure/     # Adaptadores como API, servicios HTTP, etc.
│   ├── presentation/       # Componentes standalone (UI)
│   │   ├── components/     # Componentes reutilizables
│   │   ├── pages/          # Páginas de la aplicación (rutas principales)
│   ├── state/              # Configuración de NGRX (estado global)
│   │   ├── actions/        # Acciones NGRX
│   │   ├── effects/       # Efectos NGRX
│   │   ├── reducers/       # Reducers NGRX
│   │   ├── selectors/        # Selectores NGRX
│   │   └── local.store.ts    # Store local manejado por el mfe
│   ├── app.routes.ts       # Configuración de rutas
│   ├── app.config.ts       # Configuración principal de la aplicación
│   ├── app.component.ts    # Componente principal
│   ├── app.component.html  # Template principal
│   └── app.component.scss  # Estilos principales
├── assets/                 # Recursos estáticos (imágenes, fuentes, etc.)
│   ├── federation.manifest.ts       # URLs de los mfes
├── environments/           # Configuración para diferentes entornos (desarrollo/producción)
├── bootstrap.ts           # configuración de aranque de la aplicación
despliegue/	# configuración de despliegue por entorno
ci.json	# configuración para CI
federation.config.js	# Configuración de native federation

Capas de la Arquitectura Hexagonal

Domain (Dominio)

  • Contiene los modelos de datos y las interfaces que definen las reglas del negocio.
  • Es independiente de Angular y cualquier tecnología, lo que permite reutilizar la lógica en otros entornos si es necesario.

Ubicación: src/app/domain/

 

Application (Aplicación)

  • Implementa los casos de uso y la lógica del negocio.
  • Contiene servicios que gestionan la lógica de la aplicación, interactuando con las capas de dominio e infraestructura.

Infrastructure (Infraestructura)

  • Contiene los adaptadores necesarios para interactuar con APIs externas, bases de datos, etc.
  • Su propósito es proporcionar las dependencias necesarias para los casos de uso definidos en la capa de aplicación.

Ubicación: src/app/infrastructure/

 

Core

  • Servicios y lógica central compartida: autenticación, guards e interceptores.
  • Separados en carpetas según tipo.

Ubicación: src/app/core/

 

Presentation (Presentación)

  • Contiene todos los componentes standalone y páginas que forman la interfaz de usuario.
  • Los componentes están organizados en:
    • components/: Componentes reutilizables (botones, formularios, tablas).
    • pages/: Páginas principales del proyecto (Home, Introducción, etc.).

Ubicación: src/app/presentation/

Tema bootstrap de la Junta de Andalucía

Configurar el tema Bootstrap de la Junta de Andalucía dentro del proyecto es muy importante para respetar el Sistema de diseño de la Junta. Este tema consiste en un conjunto de ficheros css y js, que están disponibles en el repositorio portal-jjaa / Tema bootstrap de la Junta de Andalucía · GitLab.

El tema Bootstrap de la Junta de Andalucía se actualiza periódicamente, cuando se introducen novedades en el Sistema de diseño de la Junta de Andalucía o por motivos técnicos (p.ej. para adaptarse a nuevas versiones del framework Bootstrap). Para facilitar el seguimiento, cada versión del tema se identifica con un número siguiendo el formato “X.X.Y” (p.ej. 1.2.6). En este esquema, los dos primeros dígitos (“X.X”) se corresponden con la versión del Sistema de diseño equivalente, mientras que “Y” indica la revisión del tema.

En los proyectos, debes integrar la última versión estable, cuyo número puedes encontrar en el repositorio del tema Bootstrap

Para la integración, hay dos opciones:

1. Integración directa en el framework

  • En el repositorio, selecciona el tag de la última versión.
  • En el directorio dist, descarga los recursos css, js y fonts necesarios. 
<link href="../dist/css/custom-jda-bootstrap.css" rel="stylesheet">
<link href="../dist/css/fonts.css" rel="stylesheet">
<link href="../dist/css/all.css" rel="stylesheet">

<script src="../dist/js/bootstrap.bundle.min.js">
<script src="../dist/js/jda-js.js">

2. Integración en línea usando el CDN

El servicio CDN de la Junta de Andalucía ofrece dos alternativas para integrar los recursos css y js necesarios:

<link href="https://cdn.juntadeandalucia.es/components/sass/X.X.Y/css/custom-jda-bootstrap.css" rel="stylesheet">
<link href="https://cdn.juntadeandalucia.es/components/sass/X.X.Y/css/fonts.css" rel="stylesheet">
<link href="https://cdn.juntadeandalucia.es/components/sass/X.X.Y/css/all.css" rel="stylesheet">

<script src="https://cdn.juntadeandalucia.es/components/sass/X.X.Y/js/bootstrap.bundle.min.js">
<script src="https://cdn.juntadeandalucia.es/components/sass/X.X.Y/js/jda-js.js">

Si incluyes latest en lugar del número de versión, integrarás siempre la versión más reciente de estos ficheros. No obstante, no se recomienda esta práctica para sistemas en producción (esto es, se recomienda enlazar a una versión determinada), ya que las actualizaciones de versiones podrían generar incidencias en la visualización del producto.

Configuración de la federación

La configuración de la federación entre la Shell y los microfontends se realiza en los ficheros federation.config.js de la Shell y de los MFEs y es esencial para habilitar Native Federation. Este archivo define los módulos que se expondrán y compartirán entre los proyectos.

Configuración en la Shell

El archivo federation.config.js de la Shell expone partes de la aplicación como el estado global y define los paquetes compartidos.

const { withNativeFederation, shareAll } = require('@angular-architects/native-federation/config');

module.exports = withNativeFederation({
 name: 'shell',
 exposes: {
   './GlobalStore': './src/app/state/global.store.ts', // Exponer el Global Store desde la Shell
 },
 shared: {
   '@ngrx/store': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@ngrx/effects': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@angular/core': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@angular/common': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@angular/router': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   ...shareAll({ singleton: true, strictVersion: false, requiredVersion: 'auto' }),
 },
});

 

Configuración en un MFE

El archivo federation.config.js de un MFE define qué módulos expone y comparte.

const { withNativeFederation, shareAll } = require('@angular-architects/native-federation/config');

module.exports = withNativeFederation({
 name: 'mfeApp',
 exposes: {
   './Component': './src/app/presentation/mfecount/mfecount.component.ts', // Componente expuesto
   './store': './src/app/state/store.ts', // Estado local
 },
 shared: {
   '@ngrx/store': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@angular/core': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   '@angular/common': { singleton: true, strictVersion: false, requiredVersion: 'auto' },
   ...shareAll({ singleton: true, strictVersion: false, requiredVersion: 'auto' }),
 },
});

 

Configuración de rutas para cargar los MFEs

El archivo app.routes.ts de la Shell debe configurarse para cargar dinámicamente los módulos de los MFEs utilizando Native Federation.

import { Routes } from '@angular/router';
import { loadRemoteModule } from '@softarc/native-federation-runtime';

export const routes: Routes = [
 {
   path: 'mfe1',
   loadChildren: () =>
     loadRemoteModule({
       remoteName: 'mfeApp',
       exposedModule: './Component',
     }).then((m) => m.MfeCountComponent),
 },
 { path: '**', redirectTo: '' },
];

 

Integración del Estado Global con NGRX

El manejo del estado global en la Shell utiliza NGRX para compartir datos entre los microfrontends.

 

Configuración del Global Store en la Shell

global.store.ts: Define el reducer y el estado inicial.

import { Action, createReducer, on } from '@ngrx/store';
import { increment } from './actions/global.actions';

export interface GlobalState {
 count: number;
}

export const initialState: GlobalState = {
 count: 0,
};

const _globalReducer = createReducer(
 initialState,
 on(increment, (state) => ({ ...state, count: state.count + 1 }))
);

export function globalReducer(state: GlobalState | undefined, action: Action) {
 return _globalReducer(state, action);
}

global.actions.ts: Define las acciones del estado global.

import { createAction } from '@ngrx/store';

export const increment = createAction('[Global] Increment');

 

Registro del Reducer en la Configuración de la Aplicación

import { provideStore } from '@ngrx/store'; 
import { globalReducer } from './state/global.store'; 
const appConfig = { providers: [ provideStore({ global: globalReducer }), ], };

 

Acceso al Estado desde un MFE

Un MFE puede suscribirse al estado global expuesto por la Shell.

import { Store } from '@ngrx/store'; 
import { Observable } from 'rxjs'; 
import { selectCount } from './global.selectors'; 
export class MfeComponent { count$: Observable<number>; 
constructor(private store: Store<{ global: { count: number } }>) { this.count$ = this.store.select(selectCount); } }

 

Comandos de Angular

Este apartado detalla los comandos más importantes de Angular CLI, especialmente los relacionados con Angular y sus nuevas características como los componentes standalone. Estos comandos permiten crear componentes, servicios, modelos y configurar rutas de manera eficiente.

Estos comandos no son exclusivos de Angular; estaban disponibles en versiones anteriores de Angular.

Crear un Componente Standalone

Un componente standalone es un componente independiente que no necesita un módulo asociado.

ng generate component nombre-del-componente –standalone

Opciones útiles:

  • --route: Crea automáticamente una ruta para el componente en el archivo de rutas.
  • --inline-template: Genera el componente con el HTML en línea.
  • --inline-style: Genera el componente con los estilos en línea.
ng generate component home --standalone --route=home

Este comando crea un componente standalone llamado home y lo registra automáticamente en las rutas.

 

Crear un Servicio

Los servicios en Angular encapsulan lógica de negocio o lógica compartida entre componentes.

ng generate service nombre-del-servicio

Opciones útiles:

  • --project: Especifica el proyecto donde se generará el servicio (si hay múltiples proyectos).
ng generate service person

Esto crea un servicio llamado person.service.ts en la carpeta correspondiente.

 

Crear un Modelo

Angular CLI no incluye un comando directo para generar modelos, pero puedes crearlo manualmente:

touch src/app/models/nombre-del-modelo.ts

Ejemplo de contenido del modelo:

export interface Person {
  id: number;
  name: string;
  age: number;
}

Para automatizar esta tarea, se puede crear un script personalizado o usar herramientas de scaffolding adicionales.

 

Crear una Ruta Standalone

Angular permite crear rutas directamente asociadas con un componente standalone.

ng generate component nombre-del-componente --standalone --route=nombre-de-la-ruta

ng generate component profile --standalone --route=profile

Esto genera un componente profile y agrega la ruta /profile automáticamente al archivo app.routes.ts.

Crear una Directiva

Las directivas permiten agregar comportamientos personalizados a elementos HTML.

ng generate directive nombre-de-la-directiva

ng generate directive highlight

Esto genera un archivo highlight.directive.ts para implementar la directiva.

 

Crear un Pipe

Los pipes se utilizan para transformar datos en las plantillas de Angular.

ng generate pipe nombre-del-pipe

ng generate pipe capitalize

Esto crea un pipe capitalize que puede transformar texto en mayúsculas o cualquier formato deseado.

 

Crear un Módulo (Opcional)

Aunque Angular promueve los componentes standalone, aún puedes crear módulos si los necesitas.

ng generate module nombre-del-modulo

ng generate module admin

Esto crea un módulo llamado admin dentro de su propia carpeta.

 

Ejecutar Pruebas

Angular CLI proporciona comandos para ejecutar pruebas unitarias.

ng test

Pruebas Unitarias con Reporte de Cobertura:

ng test --code-coverage

 

Construir la Aplicación

Genera una versión optimizada para producción.

ng build --configuration production

Ejemplo para desarrollo continuo (watch mode):

ng build --watch --configuration development

 

Lint y Formateo

Para verificar y corregir problemas de estilo de código:

ng lint

Formatear el código con Prettier:

npm run format

 

Novedades de Angular y Angular CLI
  1. Componentes Standalone:
    • Simplifican la estructura eliminando la necesidad de módulos.
    • Facilitan la modularidad y el uso de dependencias específicas en cada componente.
  2. Optimización del Build:
    • Los tiempos de compilación son más rápidos gracias a mejoras en el motor de compilación.
  3. Soporte para TypeScript 5.x:
    • Se incluye compatibilidad con las últimas versiones de TypeScript.
  4. Integración con Redux DevTools:
    • Simplifica la depuración del estado con herramientas avanzadas.

Para obtener más información se recomienda consultar la documentación oficial de Angular CLI y Angular.

 

Explicación de Scripts

El archivo package.json del proyecto contiene una serie de scripts que automatizan tareas comunes en el desarrollo, como la compilación, pruebas unitarias, linting, y formateo de código. Estos scripts están diseñados para simplificar el flujo de trabajo y mejorar la productividad de los desarrolladores.

A continuación se explica cada script definido en el archivo package.json:

Script ComandoPropósito 
ngngAlias para ejecutar comandos de Angular CLI
startng serveInicia el servidor de desarrollo y carga la aplicación en http://localhost:4200
buildng buildConstruye la aplicación para producción en la carpeta dist/
watchng build --watch --configuration developmentConstruye la aplicación en modo desarrollo y observa cambios en tiempo real
testng testEjecuta las pruebas unitarias configuradas con Karma y Jasmine
test:coverageng test --code-coverageEjecuta las pruebas unitarias y genera un reporte de cobertura en coverage/index.html
test:headlessng test --watch=false --browsers=ChromeHeadlessEjecuta las pruebas unitarias en modo "headless" (sin interfaz gráfica).
lintng lintEjecuta el análisis estático de código para asegurar que cumple con las reglas definidas
formatprettier --write "src/**/*.ts"Formatea automáticamente el código TypeScript usando Prettier

 

Pruebas

Herramientas, métodos y estrategias empleadas para garantizar la calidad del proyecto SPA. Las pruebas unitarias están respaldadas por herramientas como Karma, Jasmine.

Pruebas Unitarias

  1. Karma: Ejecuta las pruebas en navegadores.
  2. Jasmine: Framework de pruebas que define y organiza los casos de prueba.

 

Configuración de Pruebas Unitarias

Jasmine no requiere configuración explícita en el proyecto Angular, ya que se integra automáticamente con Karma a través de Angular CLI. Sin embargo, puedes personalizar comportamientos añadiendo configuraciones en los archivos .spec.ts o modificando el archivo karma.conf.js.

 

Archivo de Configuración: karma.conf.js Este archivo ya incluye karma-jasmine como framework y plugin predeterminado:

module.exports = function (config) {
  config.set({
    frameworks: [‘jasmine’, ‘@angular-devkit/build-angular’],
    plugins: [
      require(‘karma-jasmine’),
      require(‘karma-chrome-launcher’),
      require(‘karma-jasmine-html-reporter’),
      require(‘karma-coverage’),
      require(‘@angular-devkit/build-angular/build-angular/plugins/karma’),
    ],
    reporters: [‘progress’, ‘kjhtml’],
    browsers: [‘Chrome’],
    singleRun: false,
  });
};

 

Definición de Casos de Prueba con Jasmine Los casos de prueba se escriben utilizando la función global describe para definir el grupo de pruebas, it para las pruebas individuales, y expect para las expectativas:

describe(‘Grupo de Pruebas’, () => {
  it(‘debería sumar correctamente dos números’, () => {
    const resultado = 2 + 3;
    expect(resultado).toBe(5);
  });
});

Ejemplo Completo de Prueba Unitaria para un componente Standalone:

Archivo home.component.spec.ts:

import { TestBed } from ‘@angular/core/testing’;
import { HomeComponent } from ‘./home.component’;

describe(‘HomeComponent’, () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [HomeComponent],
    }).compileComponents();
  });

  it(‘debería crearse’, () => {
    const fixture = TestBed.createComponent(HomeComponent);
    const component = fixture.componentInstance;
    expect(component).toBeTruthy();
  });

  it(‘debería renderizar el título correctamente’, () => {
    const fixture = TestBed.createComponent(HomeComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement as HTMLElement;
    expect(compiled.querySelector('h1')?.textContent).toContain(‘Lista de personas’);
  });
});

 

Errores Comunes

En este apartado se describen los errores más comunes que pueden surgir durante el desarrollo, pruebas y despliegue del proyecto SPA, junto con soluciones prácticas para resolverlos. Se organiza por áreas clave como configuración del entorno, ejecución, pruebas y producción.

 

Errores en la Configuración del Entorno

ErrorPosible CausaSolución
"ng: command not found"Angular CLI no está instalado globalmenteInstala Angular CLI con: npm install -g @angular/cli
"Cannot find module '@angular/core'"Las dependencias no están instaladas correctamenteEjecuta npm install para instalar las dependencias
Versiones incompatibles de Node.jsEl proyecto requiere una versión específica de Node.jsUsa un gestor de versiones como nvm para cambiar a la versión recomendada
"Prettier not found" o errores de formatoPrettier no está instalado o configurado correctamenteAsegúrate de tener Prettier instalado: npm install --save-dev prettier.

 

Errores al hacer el npm install

Error en la librería @matter que es la de referencia del storybook.

Texto

Descripción generada automáticamente

Solución:

Crear el archivo .npmrc y añadir siguiente línea en el archivo

@matter:registry=https://nexus.paas.junta-andalucia.es/repository/msd.npm-private/ 

 

Errores en la Ejecución

ErrorPosible CausaSolución
"Port already in use" al ejecutar npm run startOtro proceso está usando el puerto 4200Cambia el puerto con: npm run start -- --port=4300
"An unhandled exception occurred: Cannot find module"Dependencias faltantes o incompatibles en el proyectoEjecuta npm install o elimina node_modules y reinstala: rm -rf node_modules && npm install
"ERROR Error: StaticInjectorError"Un servicio no está registrado correctamente en el módulo o como providedIn: 'root'Verifica la configuración de inyección en el archivo del servicio
"ExpressionChangedAfterItHasBeenCheckedError"Cambios en una propiedad después de la detección de cambios inicialUsa ChangeDetectorRef.detectChanges() o evita actualizar valores en ciclos de vida tardíos

 

Errores en Pruebas Unitarias

ErrorPosible CausaSolución
"Uncaught Error: Module not found"Falta importar el módulo o componente necesario en el archivo .spec.tsAsegúrate de que todos los módulos y dependencias estén importados en TestBed.configureTestingModule
Cobertura de código incompletaArchivos de prueba faltantes o no incluidos en el reporteAsegúrate de que todos los archivos están probados y que Karma está configurado correctamente
"No provider for Service"El servicio no está registrado en el TestBedUsa providers: [MyService] en la configuración de TestBed

 

Mejores Prácticas para la Resolución de Errores

  1. Revisar Logs de Error:
    • Inspecciona los mensajes de error en la consola o en las herramientas de desarrollo del navegador.
  2. Pruebas Aisladas:
    • Si el error ocurre en un componente o servicio, prueba ese módulo de manera aislada.
  3. Limpieza del Entorno:
    • Limpia y reinstala las dependencias con:
rm -rf node_modules package-lock.json
npm install
  1. Depuración:
    • Usa herramientas como Redux DevTools, depuradores del navegador o console.log estratégicamente para identificar la causa raíz.

 

Versiones de componentes

  • Angular: 18.x
  • ngrx: 18.x
  • node: 22.x
  • npm: 10.x
  • Generator-ada-fwk-webapps: 1.0.2

 

Para revisar la compatibilidad de Angular con otras herramientas y frameworks, puedes visitar: https://angular.dev/reference/versions

 

 

Repositorio de código de la aplicación

Cuando se desarrolla una aplicación de microfrontends es obligatorio que el código esté alojado en un repositorio de código remoto que permita el alojamiento de proyectos, la colaboración en equipo, el control de versiones, la automatización de ciertas tareas y la integración con herramientas externas.

Existe un Repositorio de Código corporativo de la Junta de Andalucía de uso obligatorio para todos los proyectos. Además, el correcto uso de este repositorio se encuentra gobernado por una serie de normas que definen la Estrategia de Ramificación del mismo.

En el ámbito de desarrollo de una aplicación de microfrontends tendremos un repositorio de código para la shell y un repositorio para cada uno de los microfrontends que formar parte de la aplicación. Esto nos permite conseguir:

  • Independencia en el desarrollo de cada una de las partes de la aplicación.
  • Desacoplamiento entre ellas.
  • Independencia de despliegue.

 

Calidad de la aplicación

La construcción de los microfrontales debe de realizarse con un diseño y codificación de calidad. Existen muchos recursos que nos pueden ayudar en ese cometido, pero desde la Agencia si se establece unos criterios normalizados de forma que la medición de la calidad del software no sea subjetiva.

Puede consultar más en información en:

 

Construcción y despliegue

En el caso de los proyectos que están almacenado en el Repositorio de Código asociado a la Plataforma de Pre-Cloud, estaría integrado en la Plataforma de CI/CD, el cual tendrá un Pipeline asociado al proyecto que se encargará de realizar todo el proceso, desde la construcción, pruebas hasta el despliegue en la plataforma de destino. 

Para el correcto despliegue de la Shell o de un mfe, estos deben tener configurado los siguientes elementos: 

  • Fichero dockerfile: Contiene la imagen base para el despliegue del componente y cualquier otro elemento necesario para la generación de la imagen.
  • Fichero ci.json: Contiene la configuración de los parámetros de entrada para la correcta ejecución del pipeline de Jenkins.
  • Directorio despliegue: Este directorio contiene una carpeta para cada entorno (test, pre y pro). Cada carpeta contiene los ficheros necesarios para el despliegue en ese entorno. El contenido de esta carpeta sigue el patrón de despliegue de Kubernetes Kustomize

Para iniciar el proceso de despliegue hay que seguir el procedimiento indicado en la documentación relativa a la estrategia de ramificación y verificar tanto en Jenkins como en ArgoCD y Openshift que el proceso de despliegue se está ejecutando correctamente.

 

Configuración despliegue MFE

Para que la comunicación entre la shell y el MFE sea correcta en el entorno de despliegue debemos habilitar CORS en el fichero de configuración de NGINX del MFE.

Ejemplo de configuración del fichero nginx.conf del MFE:

...
server {
    server_name DOMINIO_MFE #p.ej. mfeapp-map—reute-test.apps.paas-des-cica.junta-andalucia.es;
    ...
    location / {
        ...
        # Headers CORS para permitir peticiones desde la shell
        add_header ‘Access-Control-Allow-Origin’ ‘DOMINIO_SHELL’ always; #p.ej. ‘https://poc-map-shell-route-test.apps.paas-des-cica.junta-andalucia.es’
       add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
        add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, PUT, DELETE, OPTIONS’ always;
        add_header ‘Access-Control-Allow-Headers’ ‘Origin, Content-Type, Accept, Authorization’ always;

        # Manejar peticiones OPTIONS para preflight CORS
        if ($request_method = ‘OPTIONS’) {
            add_header ‘Access-Control-Allow-Origin’ ‘DOMINIO_SHELL’ always;
           add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
            add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, PUT, DELETE, OPTIONS’ always;
            add_header ‘Access-Control-Allow-Headers’ ‘Origin, Content-Type, Accept, Authorization’ always;
            add_header ‘Access-Control-Max-Age' 1728000;
            add_header ‘Content-Type’ ‘text/plain charset=UTF-8';
            add_header ‘Content-Length’ 0;
            return 204;
        }
    }
   
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
          ...
          #Headers CORS
          add_header ‘Access-Control-Allow-Origin’ ‘DOMINIO_SHELL’ always;
         add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
    }

    location ~* \.(woff2?|eot|ttf|otf)$ {
          ...
          #Headers CORS
          add_header ‘Access-Control-Allow-Origin’ ‘DOMINIO_SHELL’ always;
         add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
    }
}

 

Ficheros de configuración de despliegue

Tal y como se ha indicado anteriormente se utiliza el patrón de despliegue de Kubernetes Kustomize para realizar los despliegues de forma automática en los diferentes entornos.  Es una herramienta que permite personalizar manifiestos de Kubernetes sin necesidad de usar plantillas.

Para la implementación de este patrón tenemos la carpeta despliegue en la raíz del proyecto conteniendo una carpeta por cada uno de los entornos en los que se puede desplegar (test, pre y pro).

Dentro de cada una de estas carpetas encontramos estos ficheros:

  • kustomization.yaml: El archivo principal de Kustomize que define:
    • Qué recursos incluir en el despliegue.
    • Transformaciones para aplicar.
    • Variables de entorno.
    • Prefijos/sufijos para los nombres de recursos.
  • nombre-app-deploy.yaml: Define el deployment de Kubernetes que especifica:
    • Imagen del contenedor a desplegar.
    • Número de réplicas.
    • Configuración de recursos (CPU, memoria).
    • Variables de entorno.
    • Health checks.
    • Estrategia de despliegue.
  • nombre-app-svc.yaml: Define el Service que:
    • Expone la aplicación internamente en el cluster.
    • Especifica los puertos donde escucha la app.
    • Configura el balanceador de carga interno.
    • Define el selector para conectar con los pods.
  • nombre-app-route.yaml: Define la Route que:
    • Expone la aplicación externamente.
    • Configura el domnio/URL pública.
    • Maneja certificados SSL/TLS.
    • Define reglas de enrutamiento HTTP/HTTPS.