Saltar a contenido

Teoría del frontend

Antes de escribir una línea de Angular conviene tener claro qué problema resuelve el frontend, qué formas existen de construirlo y qué ocurre dentro del navegador cuando una SPA está funcionando. Esta página es el marco conceptual de toda la sección.


1. Frontend y backend: una frontera de responsabilidades

Una aplicación web se divide en dos grandes lados separados por la red:

Frontend Backend
Dónde se ejecuta En el navegador del usuario En el servidor
Responsabilidad Presentar información, capturar acciones, dar retroalimentación Aplicar reglas de negocio, persistir datos, autorizar
Lenguajes HTML, CSS, JavaScript / TypeScript Java, Python, C#, Node.js…
Quién lo controla El usuario (puede ver y modificar el código) La organización
Pregunta que responde ¿Cómo lo ve y lo usa la persona? ¿Es correcto, está permitido y queda guardado?
flowchart LR
    U((Usuario)) <--> F["Frontend<br/>presentación · interacción · estado de la interfaz"]
    F <-- "HTTP · JSON" --> B["Backend<br/>reglas · seguridad · persistencia"]
    B <--> DB[(Base de datos)]

Regla de oro

Todo lo que corre en el navegador está en manos del usuario: puede leerlo, modificarlo o saltárselo. Por eso el frontend nunca es el lugar de la seguridad ni de las reglas definitivas; solo las anticipa para mejorar la experiencia. La última palabra la tiene el backend.

¿Qué hace exactamente un frontend?

  1. Presentar datos de forma comprensible (tablas, tarjetas, gráficos, mapas).
  2. Capturar acciones e información del usuario (clics, formularios, búsquedas).
  3. Validar de forma temprana para dar retroalimentación inmediata.
  4. Comunicarse con una o varias APIs.
  5. Gestionar el estado de la interfaz: qué pantalla está activa, qué se está cargando, qué falló.
  6. Navegar entre vistas.
  7. Ser accesible, rápido y funcionar en distintos dispositivos.

2. Modelos de renderizado: ¿quién construye el HTML?

La decisión arquitectónica más importante de un frontend es dónde y cuándo se genera el HTML que ve el usuario.

MPA / Server-Side Rendering clásico

Multi-Page Application. Cada URL es una página distinta que el servidor construye en cada petición. Es lo que hicimos con Thymeleaf; también JSP, PHP, Django o ASP.NET MVC.

sequenceDiagram
    participant N as Navegador
    participant S as Servidor
    N->>S: GET /students
    S->>S: consulta BD + plantilla
    S-->>N: HTML completo
    N->>S: GET /students/42 (clic en enlace)
    S-->>N: HTML completo (recarga total)

SPA / Client-Side Rendering (CSR)

Single Page Application. El servidor entrega un HTML casi vacío y un paquete de JavaScript; el navegador construye todas las vistas y solo pide datos a la API. Es el modelo de Angular, React o Vue en su forma básica.

sequenceDiagram
    participant N as Navegador
    participant W as Servidor web
    participant A as API REST
    N->>W: GET / (una sola vez)
    W-->>N: index.html + main.js
    N->>N: Angular arranca y dibuja la vista
    N->>A: GET /api/students
    A-->>N: JSON
    N->>N: clic → Router cambia la vista (sin recarga)
    N->>A: GET /api/students/42
    A-->>N: JSON

SSR con hidratación

Híbrido moderno: el servidor ejecuta el mismo código del framework para entregar HTML ya armado (primera carga rápida y buena para buscadores), y luego el navegador "hidrata" esa página, es decir, le conecta los eventos y la convierte en SPA. Angular lo ofrece como Angular SSR; en React existe Next.js y en Vue, Nuxt.

SSG: generación estática

El HTML de todas las páginas se genera una sola vez, al compilar, y se publica como archivos estáticos. Ideal para contenido que cambia poco: blogs, documentación… este mismo sitio se genera así con MkDocs.

Comparación

Modelo Quién arma el HTML Cuándo Primera carga Navegación SEO Ejemplos
MPA / SSR clásico Servidor En cada petición Rápida Recarga completa Excelente Thymeleaf, JSP, PHP
SPA / CSR Navegador En ejecución Más lenta (descarga JS) Fluida, sin recarga Requiere ayuda Angular, React, Vue
SSR + hidratación Servidor y luego navegador Petición + ejecución Rápida Fluida Excelente Angular SSR, Next.js, Nuxt
SSG Herramienta de build Al compilar Muy rápida Recarga (o SPA) Excelente MkDocs, Astro, Hugo

No hay un modelo ganador

La elección depende del producto. Un portal de noticias necesita SEO y primera carga rápida (SSR/SSG). Un sistema administrativo detrás de un login —como el caso de estudio o el proyecto del curso— privilegia la interacción fluida: ahí una SPA es la opción natural.


3. ¿Cómo funciona una SPA por dentro?

3.1 Una sola página, muchas vistas

El navegador solo carga index.html una vez. Dentro hay un punto de montaje (<app-root>), y el framework reemplaza su contenido según la vista activa. Lo que se mantiene (menú, encabezado) no se vuelve a dibujar.

3.2 Enrutamiento en el cliente

¿Cómo cambia la URL sin pedir otra página al servidor? Con la History API del navegador:

history.pushState({}, '', '/students/42');   // cambia la URL, NO hace petición
window.addEventListener('popstate', () => {   // botón "atrás"
  // el router lee location.pathname y dibuja la vista correspondiente
});

El router del framework envuelve este mecanismo: intercepta los clics en enlaces internos, actualiza la URL con pushState y decide qué componente mostrar.

flowchart LR
    C[Clic en routerLink] --> P["history.pushState('/students/42')"]
    P --> R[Router busca la ruta que coincide]
    R --> V[Destruye la vista anterior<br/>y crea StudentDetailComponent]
    V --> D[El componente pide datos a la API]

Consecuencia para el despliegue

Si el usuario recarga /students/42, la petición sí llega al servidor web, que no tiene ese archivo. Por eso el servidor debe responder siempre index.html para rutas desconocidas (fallback); Angular arranca y resuelve la ruta en el cliente.

3.3 Reactividad: del dato a la pantalla

En JavaScript actualizábamos el DOM a mano. Un framework invierte esa responsabilidad: declaramos cómo debe verse la vista en función del estado, y el framework se encarga de sincronizarla cuando el estado cambia.

// Hay que recordar actualizar CADA lugar donde aparece el dato
contador++;
document.querySelector('#total').textContent = contador;
document.querySelector('#badge').textContent = contador;
if (contador > 0) document.querySelector('#vacio').hidden = true;
<!-- Se describe el resultado; Angular actualiza todo al cambiar el estado -->
<span>{{ contador() }}</span>
<span class="badge">{{ contador() }}</span>
@if (contador() === 0) { <p>Sin elementos</p> }
flowchart LR
    E[Evento<br/>clic, respuesta HTTP] --> S[Cambia el estado]
    S --> F[El framework detecta el cambio]
    F --> V[Actualiza solo las partes<br/>del DOM afectadas]
    V --> E

Cada framework detecta los cambios de forma distinta:

Estrategia Idea Quién la usa
Detección de cambios Tras cada evento, revisar los bindings del árbol de componentes Angular (Zone.js)
Virtual DOM Generar una copia ligera del DOM, compararla con la anterior (diffing) y aplicar solo diferencias React, Vue
Signals / reactividad fina Cada valor sabe qué partes de la vista dependen de él y solo esas se actualizan Angular (signals), Solid, Vue, Svelte

3.4 Estado de la interfaz

El estado es toda la información que determina qué se ve en un momento dado. Conviene distinguir sus tipos:

Tipo de estado Ejemplo Dónde vive en Angular
Local de un componente Un menú desplegado, el texto de un campo Propiedad o signal del componente
Compartido Usuario autenticado, proyecto seleccionado Servicio providedIn: 'root'
En la URL /students/42?page=2 Router (parámetros)
Del servidor La lista de estudiantes API; el frontend guarda una copia temporal

La URL también es estado

Si una vista depende de un filtro o una página, ponerlo en la URL permite recargar, compartir el enlace y usar el botón atrás sin perder el contexto.


4. Arquitectura basada en componentes

Todos los frameworks modernos coinciden en una idea: la interfaz se construye como un árbol de componentes, cada uno con su propia estructura, estilo y comportamiento.

flowchart TD
    A[App] --> H[Header]
    A --> M[Menú]
    A --> P[Página: listado de estudiantes]
    P --> F[Filtro]
    P --> L[Lista]
    L --> C1[Tarjeta]
    L --> C2[Tarjeta]
    L --> C3[Tarjeta]

Principios que guían el diseño:

  • Responsabilidad única: cada componente resuelve una necesidad visual concreta.
  • Encapsulamiento: sus estilos y su lógica no se filtran a otros componentes.
  • Composición: pantallas complejas se arman combinando piezas simples.
  • Flujo de datos unidireccional: los datos bajan (de padre a hijo); los eventos suben (de hijo a padre).
  • Contenedores y presentacionales: unos componentes coordinan (piden datos, deciden), otros solo muestran lo que reciben. Los segundos son los más reutilizables.

5. El ecosistema de herramientas

Un proyecto frontend moderno no se escribe directamente en el JavaScript que ejecuta el navegador. Pasa por una cadena de construcción (build):

flowchart LR
    TS["Código fuente<br/>TypeScript · HTML · CSS"] --> T["Compilar / transpilar<br/>TS → JS"]
    T --> B["Empaquetar (bundle)<br/>muchos archivos → pocos"]
    B --> O["Optimizar<br/>tree-shaking · minificar"]
    O --> D["dist/<br/>archivos estáticos"]
Concepto Qué significa
npm Gestor de paquetes: descarga las dependencias declaradas en package.json a node_modules/
Transpilar Convertir TypeScript (o JS moderno) a JavaScript que el navegador entiende
Bundler Une cientos de módulos en unos pocos archivos (Angular usa esbuild / Vite)
Tree-shaking Eliminar el código importado que nunca se usa
Minificar Quitar espacios y acortar nombres para reducir el tamaño
Lazy loading Dividir el bundle en partes (chunks) que se descargan solo cuando se necesitan
Dev server Servidor local con recarga automática al guardar (ng serve)

El resultado de ng build son archivos estáticos: se pueden publicar en cualquier servidor web (nginx, un bucket, un CDN), sin Java ni Node en producción.

Frameworks y librerías

Herramienta Tipo Lenguaje Características
Angular Framework completo TypeScript Estructura definida: router, HTTP, formularios, DI, CLI. Muy usado en entornos empresariales
React Librería de UI JavaScript / TS (JSX) Solo la vista; el resto (router, estado) se elige aparte. Ecosistema enorme
Vue Framework progresivo JavaScript / TS Curva de aprendizaje suave; se puede adoptar por partes
Svelte Compilador JavaScript / TS Convierte componentes en JS optimizado al compilar, sin runtime pesado

¿Por qué Angular en este curso?

Porque es opinado: impone una forma de organizar el código (componentes, modelos, servicios, rutas) muy parecida a las capas que ya construimos en Spring Boot. Los conceptos —componentes, reactividad, routing, consumo de APIs— se transfieren a cualquier otro framework.


6. Calidad de un frontend

Que la aplicación "funcione" no es suficiente. Un buen frontend se evalúa también en estas dimensiones:

Rendimiento

Métrica (Core Web Vitals) Qué mide Objetivo
LCP · Largest Contentful Paint Cuánto tarda en verse el contenido principal < 2,5 s
INP · Interaction to Next Paint Cuánto tarda la interfaz en responder a una interacción < 200 ms
CLS · Cumulative Layout Shift Cuánto "salta" el contenido mientras carga < 0,1

Buenas prácticas: carga perezosa de rutas, imágenes optimizadas, no descargar datos que no se muestran, paginar listas largas.

Accesibilidad (a11y)

La aplicación debe poder usarse con teclado, lector de pantalla o con baja visión:

  • Usar HTML semántico (<button>, <nav>, <main>, <label>) en lugar de <div> para todo.
  • Asociar cada campo con su <label>.
  • Contraste de color suficiente y no comunicar información solo con color.
  • Que todo lo que se hace con el mouse se pueda hacer con el teclado.

Seguridad en el navegador

Riesgo Qué es Cómo se mitiga
XSS (Cross-Site Scripting) Inyectar JavaScript malicioso a través de datos mostrados en la página Angular escapa automáticamente {{ }}; evitar innerHTML con datos no confiables
CSRF Que otro sitio haga peticiones en nombre del usuario autenticado Tokens en cabecera (Authorization: Bearer) en lugar de solo cookies; protección CSRF en el backend
CORS Política del navegador que bloquea peticiones a otro origen salvo autorización El backend declara qué orígenes acepta
Exposición de secretos Poner claves o contraseñas en el código del frontend Nunca: todo el código del frontend es público

Experiencia de usuario

Toda operación asíncrona tiene cuatro estados que la interfaz debe representar: inactivo, cargando, éxito y error. Una pantalla que se queda en blanco mientras carga o que no explica un fallo se percibe como rota, aunque el backend funcione. (Ver Excepciones.)


7. Glosario rápido

Término Definición breve
DOM Representación en árbol del documento HTML que el navegador mantiene en memoria y que JavaScript puede modificar
SPA Aplicación que carga una sola página y cambia las vistas en el navegador
MPA Aplicación donde cada navegación pide una página completa al servidor
CSR / SSR / SSG Renderizado en cliente / en servidor / al compilar
Hidratación Conectar eventos y estado a un HTML que llegó ya generado desde el servidor
Componente Pieza reutilizable de interfaz con su HTML, estilos y lógica
Binding Conexión automática entre un dato y la vista
Estado Información que determina qué se muestra en un momento dado
Router Pieza que asocia URLs con vistas sin recargar la página
API REST Interfaz HTTP que expone recursos en formato JSON
Bundle Archivo(s) JavaScript resultante(s) de empaquetar la aplicación
Observable Fuente de valores asíncronos a la que uno se suscribe (RxJS)
Signal Valor reactivo que notifica a Angular cuando cambia

Pregunta de reflexión

El proyecto del curso es un sistema de gestión de procesos con login, roles y edición de diagramas. ¿Qué modelo de renderizado elegirías y por qué? ¿Qué parte del sistema podría beneficiarse de otro modelo (por ejemplo, una página pública de presentación)?

Siguiente: Generalidades de Angular.