Angular SSR: Optimización para SEO y Performance

10 de diciembre de 2025
Osman Jimenez
Angular SEO Performance

Server-Side Rendering en Angular

El SSR (Server-Side Rendering) en Angular mejora drásticamente el SEO y el tiempo de carga inicial. Aprende a implementarlo y optimizarlo correctamente.

Configuración Inicial

// Agregar SSR a proyecto existente
ng add @angular/ssr

// Ejecutar en modo SSR
npm run dev:ssr
npm run build:ssr
npm run serve:ssr

Manejo de APIs del Navegador

El código SSR se ejecuta en Node.js, donde no existen APIs del navegador:

import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';

export class MyComponent {
  private platformId = inject(PLATFORM_ID);
  
  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      // Código que usa window, document, localStorage
      const data = localStorage.getItem('key');
      window.addEventListener('scroll', this.onScroll);
    }
  }
}

TransferState para Evitar Doble Petición

import { TransferState, makeStateKey } from '@angular/platform-browser';

const USERS_KEY = makeStateKey('users');

export class UserService {
  private transferState = inject(TransferState);
  private http = inject(HttpClient);
  
  getUsers(): Observable {
    // Verificar si ya tenemos los datos del servidor
    const cachedUsers = this.transferState.get(USERS_KEY, null);
    
    if (cachedUsers) {
      // Limpiar para evitar fugas de memoria
      this.transferState.remove(USERS_KEY);
      return of(cachedUsers);
    }
    
    // Hacer petición y guardar en TransferState
    return this.http.get('/api/users').pipe(
      tap(users => {
        if (isPlatformServer(this.platformId)) {
          this.transferState.set(USERS_KEY, users);
        }
      })
    );
  }
}

Meta Tags Dinámicos para SEO

import { Meta, Title } from '@angular/platform-browser';

export class ProductDetailComponent {
  private meta = inject(Meta);
  private title = inject(Title);
  
  ngOnInit() {
    this.productService.getProduct(this.id).subscribe(product => {
      // Título
      this.title.setTitle(`${product.name} - Mi Tienda`);
      
      // Meta tags
      this.meta.updateTag({ 
        name: 'description', 
        content: product.description 
      });
      
      // Open Graph
      this.meta.updateTag({ 
        property: 'og:title', 
        content: product.name 
      });
      this.meta.updateTag({ 
        property: 'og:image', 
        content: product.imageUrl 
      });
      this.meta.updateTag({ 
        property: 'og:description', 
        content: product.description 
      });
      
      // Twitter Card
      this.meta.updateTag({ 
        name: 'twitter:card', 
        content: 'summary_large_image' 
      });
    });
  }
}

Prerendering de Rutas Estáticas

// angular.json
{
  "projects": {
    "my-app": {
      "architect": {
        "prerender": {
          "options": {
            "routes": [
              "/",
              "/about",
              "/contact",
              "/products/1",
              "/products/2"
            ]
          }
        }
      }
    }
  }
}

Optimizaciones de Performance

1. Lazy Loading de Imágenes

2. Defer Loading de Componentes

@defer (on viewport) {
  
} @placeholder {
  
Cargando...
}

Manejo de Errores en SSR

// server.ts
server.get('*', (req, res, next) => {
  const { protocol, originalUrl, baseUrl, headers } = req;
  
  commonEngine
    .render({
      bootstrap,
      documentFilePath: indexHtml,
      url: `${protocol}://${headers.host}${originalUrl}`,
      publicPath: browserDistFolder,
      providers: [
        { provide: APP_BASE_HREF, useValue: baseUrl }
      ]
    })
    .then((html) => res.send(html))
    .catch((err) => {
      console.error('SSR Error:', err);
      res.status(500).send('Error rendering page');
    });
});

Testing SSR

// Verificar que el componente funciona en ambos entornos
describe('MyComponent SSR', () => {
  it('should work on server', () => {
    TestBed.configureTestingModule({
      providers: [
        { provide: PLATFORM_ID, useValue: 'server' }
      ]
    });
    
    const fixture = TestBed.createComponent(MyComponent);
    expect(fixture.componentInstance).toBeTruthy();
  });
});

Mejores Prácticas

  1. Evita código específico del navegador: Usa isPlatformBrowser
  2. Usa TransferState: Para evitar peticiones duplicadas
  3. Meta tags dinámicos: Actualiza SEO por ruta
  4. Prerender rutas estáticas: Para mejor performance
  5. Manejo de errores: Implementa fallbacks robustos

Conclusión

Angular SSR es esencial para aplicaciones que necesitan buen SEO y tiempos de carga rápidos. Con estas técnicas puedes implementar SSR de forma efectiva y evitar los problemas comunes.