En esta página
SSR, pre-rendering y despliegue
Qué es SSR?
Server-Side Rendering (SSR) genera el HTML de tu aplicación en el servidor antes de enviarlo al navegador. Beneficios:
- SEO mejorado — Los bots de busqueda leen HTML completo
- Primera carga rápida — El usuario ve contenido inmediatamente
- Social sharing — Meta tags disponibles para Open Graph
Modos de renderizado en Angular 21
Angular 21 define tres modos en ServerRoute:
| Modo | Descripcion | Cuando usar |
|---|---|---|
RenderMode.Prerender |
HTML generado en build time | Páginas estaticas (home, about, blog) |
RenderMode.Server |
HTML generado por request | Páginas dinamicas (perfiles, busqueda) |
RenderMode.Client |
Solo renderizado en el navegador | Dashboard, admin, contenido privado |
Configurar SSR
Al crear un proyecto con ng new, Angular pregunta si quieres SSR. Si ya tienes un proyecto, agregalo con:
ng add @angular/ssrEsto genera:
src/app/app.config.server.ts— Configuración del servidorsrc/app/app.routes.server.ts— Rutas con modos de renderizadoserver.ts— Servidor Express
Rutas del servidor
Define como se renderiza cada ruta:
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
// Pre-renderizar en build
{ path: '', renderMode: RenderMode.Prerender },
{ path: 'blog', renderMode: RenderMode.Prerender },
// Pre-renderizar con parametros (genera un HTML por slug)
{
path: 'blog/:slug',
renderMode: RenderMode.Prerender,
async getPrerenderParams() {
return [
{ slug: 'introduccion-angular' },
{ slug: 'signals-tutorial' },
{ slug: 'ssr-guia-completa' },
];
},
},
// SSR dinámico
{ path: 'buscar', renderMode: RenderMode.Server },
// Solo cliente
{ path: 'dashboard/**', renderMode: RenderMode.Client },
];Deteccion de plataforma
Algunos APIs solo existen en el navegador. Usa isPlatformBrowser para proteger ese código:
import { isPlatformBrowser, PLATFORM_ID } from '@angular/common';
import { inject } from '@angular/core';
const platformId = inject(PLATFORM_ID);
if (isPlatformBrowser(platformId)) {
// Seguro: estamos en el navegador
window.scrollTo(0, 0);
localStorage.setItem('key', 'value');
}afterNextRender y afterRender
Para código que debe ejecutarse solo despues del renderizado en el navegador:
import { afterNextRender } from '@angular/core';
constructor() {
afterNextRender(() => {
// Se ejecuta una vez, solo en el navegador
// Ideal para inicializar librerias de terceros
this.chart = new Chart(this.canvasRef.nativeElement, config);
});
}Meta tags para SEO
Usa los servicios Title y Meta para establecer meta tags server-side:
import { Title, Meta } from '@angular/platform-browser';
@Component({ /* ... */ })
export class BlogPost {
private readonly title = inject(Title);
private readonly meta = inject(Meta);
constructor() {
effect(() => {
const post = this.post();
this.title.setTitle(`${post.título} | Mi Blog`);
this.meta.updateTag({ name: 'description', content: post.resumen });
this.meta.updateTag({ property: 'og:title', content: post.título });
this.meta.updateTag({ property: 'og:image', content: post.imagen });
});
}
}Despliegue
Firebase Hosting (estático + Cloud Functions)
ng build
firebase deployDocker (SSR completo)
FROM node:20-alpine
WORKDIR /app
COPY dist/ ./dist/
COPY package.json ./
RUN npm install --production
EXPOSE 4000
CMD ["node", "dist/mi-app/server/server.mjs"]Plataformas compatibles
- Firebase Hosting — Pre-rendering estático + Cloud Functions
- Vercel — SSR serverless automático
- Netlify — Pre-rendering estático
- Railway / Render — SSR con Docker
Práctica
- Configura modos de renderizado: Define un archivo
app.routes.server.tscon al menos 3 rutas usando los tres modos:Prerenderpara la pagina principal,Serverpara rutas dinamicas yClientpara el dashboard. - Protege APIs del navegador: Crea un servicio que use
localStorage. Envuelvelo conisPlatformBrowser()para que no falle durante SSR y agrega un fallback para el servidor. - Agrega meta tags SEO: Usa los servicios
TitleyMetadentro de uneffect()para establecer el titulo de la pagina y las etiquetasdescriptionyog:titledinamicamente en un componente.
En la siguiente leccion aprenderemos los fundamentos de testing en Angular con Vitest.
RenderMode
Usa Prerender para páginas estaticas (mejor rendimiento), Server para páginas dinamicas con datos frescos, y Client para secciones que requieren autenticación o APIs del navegador.
APIs del navegador
En SSR, window, document, localStorage y sessionStorage no existen. Usa isPlatformBrowser() o afterNextRender() para ejecutar código que dependa del navegador.
// --- app.config.server.ts ---
import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { provideServerRoutesConfig } from '@angular/ssr';
import { serverRoutes } from './app.routes.server';
import { appConfig } from './app.config';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(),
provideServerRoutesConfig(serverRoutes),
],
};
export default mergeApplicationConfig(appConfig, serverConfig);
// --- app.routes.server.ts ---
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
// Páginas estaticas: se pre-renderizan en build
{ path: '', renderMode: RenderMode.Prerender },
{ path: 'blog', renderMode: RenderMode.Prerender },
{ path: 'cursos', renderMode: RenderMode.Prerender },
// Páginas con parametros: SSR en el servidor
{
path: 'blog/:slug',
renderMode: RenderMode.Server,
},
// Dashboard: solo cliente (no SSR)
{ path: 'dashboard/**', renderMode: RenderMode.Client },
// Ruta catch-all
{ path: '**', renderMode: RenderMode.Server },
];
Inicia sesión para guardar tu progreso