El Server-Side Rendering (SSR) ha sido durante mucho tiempo una debilidad de Angular comparado con frameworks como Next.js. Pero con Angular 17+, el panorama ha cambiado radicalmente gracias a la hidratación no destructiva y el nuevo sistema de SSR integrado.
¿Por qué necesitas SSR?
Sin SSR, una aplicación Angular funciona así:
- El navegador descarga un HTML vacío (
<app-root></app-root>). - Descarga y ejecuta todo el JavaScript.
- Angular renderiza la aplicación.
- El usuario finalmente ve contenido.
Esto genera:
- Mal SEO: Los crawlers ven una página vacía.
- CLS alto: El contenido “salta” al renderizarse.
- LCP lento: El primer contenido visible tarda en aparecer.
Configuración en Angular 17+
ng new mi-proyecto --ssr
# O añadir SSR a un proyecto existente:
ng add @angular/ssr
Configuración del servidor
// app.config.server.ts
import { mergeApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { provideServerRouting } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';
const serverConfig = {
providers: [
provideServerRendering(),
provideServerRouting(serverRoutes)
]
};
export default mergeApplicationConfig(appConfig, serverConfig);
Hidratación No Destructiva
// app.config.ts
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
export const appConfig = {
providers: [
provideRouter(routes),
provideClientHydration(withEventReplay()),
provideHttpClient(withFetch()),
]
};
Rutas del Servidor: Control fino
// app.routes.server.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '',
renderMode: RenderMode.Prerender
},
{
path: 'blog/:slug',
renderMode: RenderMode.Server
},
{
path: 'dashboard/**',
renderMode: RenderMode.Client
},
{
path: '**',
renderMode: RenderMode.Server
}
];
Manejo de APIs del navegador en SSR
// ❌ Esto rompe en SSR
@Component({...})
export class BadComponent {
width = window.innerWidth; // ERROR: window is not defined
}
// ✅ Solución moderna con afterNextRender
@Component({...})
export class ModernComponent {
constructor() {
afterNextRender(() => {
// Solo se ejecuta en el navegador, después del primer render
const observer = new IntersectionObserver(...);
});
}
}
Conclusión
SSR + Hydration en Angular moderno es una combinación poderosa que cierra la brecha con Next.js y Nuxt. Con provideClientHydration, rutas de servidor y pre-renderizado, puedes conseguir puntuaciones de Lighthouse cercanas a 100.