Ir al contenido

Introducción y arquitectura

Una aplicación de una sola página, servida por CDN sobre HTTPS con dominio propio, desplegada automáticamente desde GitHub, y con releases versionados por tag que se pueden revertir en un minuto.

Sin ninguna instancia que administrar.

Hoy despliegas aplicaciones TypeScript en instancias. Para una API con estado eso es una decisión razonable. Para una SPA no lo es, y vale la pena ver por qué antes de escribir código.

Una SPA compilada es un directorio de archivos estáticos: un index.html, uno o dos bundles de JavaScript, CSS y algunos assets. No ejecuta nada en el servidor. Cuando pones eso detrás de nginx en una EC2, lo que te queda es:

EC2 con nginx S3 con CloudFront
Parches del sistema operativo tuyos no existen
Certificado TLS tú lo renuevas ACM lo renueva
Alta disponibilidad otra instancia y un balanceador incluida
Latencia fuera de la región la del origen punto de presencia cercano
Escalar a un pico de tráfico escalar el grupo nada que hacer
Costo con tráfico bajo la instancia corre 24/7 centavos
┌──────────────────────────────┐
navegador ──────▶│ CloudFront (CDN + TLS) │
│ · certificado de ACM │
│ · 403/404 → /index.html │
│ · caché por tipo de archivo │
└──────────────┬───────────────┘
│ OAC (firma SigV4)
┌──────────────────────────────┐
│ S3 (bucket privado) │
│ · sin acceso público │
│ · assets con hash │
└──────────────────────────────┘

Tres piezas que importan y que vas a configurar tú:

Bucket privado con OAC

El bucket no se expone a internet. CloudFront firma cada petición al origen con Origin Access Control. Un bucket público sería más fácil y es la razón por la que existen tantas filtraciones de datos en S3.

El fallback de rutas

Tu SPA maneja /tareas/abc en el cliente, pero ese objeto no existe en S3. Sin configurar la respuesta de error, recargar la página da un 403. Lo vas a provocar y luego a arreglar.

Caché por tipo de archivo

Los assets con hash en el nombre se cachean para siempre. El index.html nunca. Si inviertes esto, tus despliegues tardan horas en verse y nadie entiende por qué.

Releases por tag

Un push a main despliega a desarrollo. Solo un tag vX.Y.Z despliega a producción, con el rol de IAM restringido a ese origen. Revertir es redesplegar el tag anterior.

Vas a construir TaskFlow, un tablero de tareas. Es deliberadamente pequeño: crear, marcar como hecha, filtrar y borrar.

Sin framework. Vite para el build, TypeScript, y una sola dependencia de runtime: @preact/signals-core, que aporta reactividad en poco más de un kilobyte. El puente al DOM lo escribes tú en unas cuarenta líneas.

En este workshop la aplicación no tiene backend: las tareas viven en el navegador y se guardan en localStorage. El backend con API Gateway, Lambda y DynamoDB es el Workshop 02, y va a consumir exactamente esta misma SPA.

  1. Preparar el entorno. Toolchain en contenedor, cuenta de AWS y presupuesto de gasto.

  2. Crear tus dos repositorios. Uno para la infraestructura y otro para la aplicación, con los entornos de GitHub y la confianza OIDC.

  3. Construir la SPA. Vite y TypeScript sin framework, con reactividad por signals y un router propio sobre la History API.

  4. Crear la infraestructura con Terraform. Bucket privado, CloudFront con OAC, y el fallback de rutas que vas a provocar y arreglar.

  5. Poner el dominio. Certificado en ACM validado por DNS, y tu subdominio en producción.

  6. Automatizar el despliegue. GitHub Actions autenticando contra AWS con OIDC, sin claves de acceso guardadas en ningún sitio.

  7. Versionar por tag. Release semántico que dispara producción, aprobación humana, y reversión en un minuto.

  8. Cerrar. Costos, qué observar, y destruir todo lo creado.

Este workshop crea recursos que cuestan dinero, aunque poco. El módulo de cierre incluye el terraform destroy y una revisión de que no quedó nada corriendo. No lo saltes.

Empieza por los prerequisitos.