Dominando Monorepositorios con NX - Parte 3
🚀 Parte 3: Integración continua, tests y despliegue
“CI/CD inteligente con Nx: testea, construye y despliega solo lo necesario”
Hasta ahora, hemos construido una base sólida: un monorepo con una arquitectura escalable y bien definida. Pero el verdadero retorno de la inversión de Nx se materializa cuando automatizamos nuestros flujos de trabajo. ¿Para qué reconstruir y testear todo el repositorio en cada commit si solo cambiaste una línea en un componente de UI?
En esta parte final, configuraremos un pipeline de CI/CD inteligente con GitHub Actions. Aprenderás a ejecutar tests y builds solo sobre el código afectado, a cachear resultados para una velocidad increíble y a desplegar tu aplicación Angular automáticamente.
1. Revisión de comandos clave: nx affected
El corazón de un CI/CD eficiente con Nx es la familia de comandos affected. Recordemos lo que hacen:
nx affected:test: Ejecuta los tests unitarios únicamente para los proyectos que han cambiado (o dependen de algo que ha cambiado) en comparación con una rama base (normalmente main o master).
nx affected:build: Construye solo las aplicaciones y librerías afectadas.
nx affected:lint: Ejecuta el linter sobre los proyectos afectados.
Estos comandos son la clave para tener pipelines rápidos y eficientes, sin importar cuán grande se vuelva tu monorepo.
2. Configuración de CI/CD con GitHub Actions
Vamos a crear un workflow de GitHub Actions que, en cada pull request, verificará que solo el código afectado pase las pruebas de linting y tests.
Crea el archivo de workflow: En la raíz de tu proyecto, crea la siguiente estructura de carpetas y el archivo: .github/workflows/ci.yml.
Define el workflow: Pega el siguiente contenido en ci.yml:
name: CI para el Monorepo on: push: branches: - main pull_request: jobs: main: runs-on: ubuntu-latest steps: - name: Checkout del código uses: actions/checkout@v4 with: # Necesitamos el historial para que 'nx affected' pueda comparar fetch-depth: 0 - name: Configurar Node.js uses: actions/setup-node@v4 with: node-version: 18 cache: 'npm' # Habilita el cacheo de dependencias de npm - name: Instalar dependencias run: npm ci - name: Derivar SHAs para Nx Affected # Este paso es crucial. Obtiene los SHAs de la rama base y la actual # para que 'nx affected' sepa qué comparar. uses: nrwl/nx-set-shas@v4 # --- Tareas de Verificación --- - name: Linting del código afectado run: npx nx affected -t lint --parallel=3 - name: Testeo del código afectado run: npx nx affected -t test --parallel=3 --configuration=ci - name: Build del código afectado run: npx nx affected -t build --parallel=3 --configuration=production
¿Qué hace este workflow?
Se activa en cada push a main y en cada pull_request.
Usa actions/checkout con fetch-depth: 0 para descargar todo el historial de Git, necesario para la comparación de affected.
Instala las dependencias usando npm ci (más rápido y seguro para CI que npm install).
La magia ocurre aquí: nrwl/nx-set-shas es una acción oficial de Nx que establece las variables de entorno NX_BASE y NX_HEAD que los comandos affected usan para saber qué ha cambiado.
Finalmente, ejecuta lint, test y build solo en los proyectos afectados. El flag --parallel=3 permite ejecutar hasta 3 tareas en paralelo, acelerando aún más el proceso.
3. Deploy automatizado a GitHub Pages
Ahora, extendamos nuestro workflow para que, cuando se haga un merge a main, la aplicación store se despliegue automáticamente en GitHub Pages.
Añade un job de despliegue: Modifica tu archivo ci.yml para añadir un segundo job que dependa del primero.
name: CI y Despliegue on: push: branches: - main pull_request: jobs: # El job 'main' que ya teníamos... main: runs-on: ubuntu-latest steps: # ... (todos los pasos anteriores sin cambios) # --- Nuevo Job de Despliegue --- deploy: # Solo se ejecuta si el job 'main' fue exitoso y estamos en la rama 'main' if: github.ref == 'refs/heads/main' && github.event_name == 'push' needs: [main] runs-on: ubuntu-latest steps: - name: Checkout del código uses: actions/checkout@v4 - name: Configurar Node.js uses: actions/setup-node@v4 with: node-version: 18 cache: 'npm' - name: Instalar dependencias run: npm ci - name: Construir la aplicación 'store' # Aquí no usamos 'affected', construimos la app específica a desplegar run: npx nx build store --configuration=production --base-href=/mi-super-monorepo/ - name: Desplegar a GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} # La carpeta que contiene el build de nuestra app publish_dir: ./dist/apps/store/browser
Puntos clave del job de despliegue:
needs: [main]: Asegura que este job solo se ejecute si el de CI (main) ha terminado con éxito.
if: ...: Condiciona la ejecución solo para los pushes a la rama main.
nx build store --base-href=/mi-super-monorepo/: Construimos la aplicación store específicamente. El --base-href es importante para que los assets se carguen correctamente en GitHub Pages, que aloja el proyecto en un subdirectorio. Reemplaza mi-super-monorepo con el nombre de tu repositorio.
peaceiris/actions-gh-pages@v3: Una popular acción que toma el contenido de publish_dir y lo publica en la rama gh-pages de tu repo, activando el despliegue.
No olvides activar GitHub Pages en la configuración de tu repositorio para que sirva desde la rama gh-pages.
4. Optimización del flujo: Nx Cloud y el caché distribuido
¿Recuerdas que al inicio habilitamos el caché distribuido? Nx Cloud lleva el caching local un paso más allá.
Cuando tu CI ejecuta nx affected -t build, si esa misma tarea ya fue ejecutada por un compañero en su máquina (con los mismos cambios), Nx Cloud puede descargar el resultado del caché en lugar de reconstruirlo. ¡Esto reduce los tiempos de CI de minutos a segundos!
Para conectar tu CI a Nx Cloud, solo necesitas añadir un NX_CLOUD_AUTH_TOKEN a los secretos de tu repositorio en GitHub y referenciarlo en tu workflow:
# En tu archivo ci.yml
- name: Linting
env:
NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }}
run: npx nx affected -t lint --parallel=3
# ... haz lo mismo para test y build
5. Buenas prácticas
Testing Unitario y E2E: Asegúrate de que tus librerías data-access y util tengan una excelente cobertura de tests unitarios. Los tests E2E (con Cypress o Playwright, ambos soportados por Nx) deben ejecutarse para las aplicaciones afectadas.
Versionado: Si planeas publicar librerías a un registro como npm, Nx tiene generadores para gestionar el versionado y la publicación de forma independiente por librería.
Variables de Entorno: Utiliza los secretos de GitHub para gestionar las variables de entorno (environment.prod.ts) de forma segura en tu CI/CD.
🎯 Objetivo Final de la Serie Cumplido:
¡Lo has logrado! Has completado el viaje desde cero hasta un monorepo profesional con Nx y Angular. A lo largo de estas tres partes, has aprendido a:
Entender y crear un workspace de Nx, comprendiendo los beneficios de la arquitectura monorepo.
Diseñar una arquitectura escalable con librerías compartidas, dominios y reglas de dependencias que mantienen tu código limpio.
Configurar un flujo CI/CD de nivel mundial que es rápido, inteligente y despliega tu aplicación automáticamente.
Ahora estás perfectamente equipado para construir, escalar y mantener proyectos Angular complejos con las mejores herramientas y prácticas de la industria. ¡Felicitaciones!