Saltar al contenido principal

[Lv3] Retos de implementación SSR y soluciones

Problemas comunes en SSR y soluciones prácticas: Hydration Mismatch, variables de entorno, compatibilidad de librerias, rendimiento y arquitectura de despliegue.


Escenario de entrevista

Pregunta: Qué problemas encontraste al implementar SSR y como los resolviste?

Qué quiere validar el entrevistador:

  1. Experiencia real: si implementaste SSR en un entorno real.
  2. Método de resolución: cómo detectas causa raiz y priorizas.
  3. Profundidad técnica: rendering, hydration, cache, despliegue.
  4. Buenas prácticas: soluciones mantenibles y medibles.

Reto 1: Hydration Mismatch

Problema

Mensaje común:

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content.

Causas frecuentes:

  • Render diferente entre servidor y cliente
  • Uso de APIs solo navegador en ruta SSR (window, document, localStorage)
  • Valores no deterministas (Date.now(), Math.random())

Soluciones

Opcion A: encapsular con ClientOnly

<template>
<div>
<h1>Contenido SSR</h1>
<ClientOnly>
<BrowserOnlyComponent />
<template #fallback>
<div>Cargando...</div>
</template>
</ClientOnly>
</div>
</template>

Opcion B: guardas en cliente

<script setup lang="ts">
const ua = ref('');

onMounted(() => {
if (process.client) {
ua.value = window.navigator.userAgent;
}
});
</script>

Idea clave de entrevista: salida SSR determinista; toda lógica browser-only aislada en cliente.


Reto 2: Variables de entorno

Problema

  • Secretos de servidor expuestos accidentalmente al cliente.
  • Uso desordenado de process.env complica trazabilidad.

Solución

Separar con runtime config:

// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: process.env.API_SECRET,
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE,
},
},
});
// uso
const config = useRuntimeConfig();
const apiBase = config.public.apiBase; // cliente + servidor
const secret = config.apiSecret; // solo servidor

Idea clave: secretos solo en servidor, valores públicos en bloque public.


Reto 3: Librerias de terceros sin soporte SSR

Problema

  • Algunas librerias tocan DOM durante SSR.
  • Resultado: errores de build/runtime o hydration inconsistente.

Soluciones

  1. Cargar libreria solo en cliente (plugin .client.ts)
  2. Import dinámico en contexto cliente
  3. Evaluar alternativa SSR-friendly
let chartLib: any;
if (process.client) {
chartLib = await import('chart.js/auto');
}

Idea clave: primero aislar causa, luego aplicar client-isolation o cambiar libreria.


Reto 4: Manejo de cookies y headers

Problema

  • SSR con auth requiere leer cookies en servidor.
  • Headers deben mantenerse consistentes entre cliente, SSR y API.

Solución

const token = useCookie('access_token');

const { data } = await useFetch('/api/me', {
headers: process.server
? useRequestHeaders(['cookie'])
: undefined,
credentials: 'include',
});

Idea clave: una request SSR no debe perder contexto de autenticación.


Reto 5: Timing en carga asíncrona

Problema

  • Múltiples componentes piden el mismo recurso.
  • Hay requests duplicados y estados de carga inconsistentes.

Solución

  • Definir keys unificados para deduplication
  • Centralizar acceso a datos en composables
  • Separar carga inicial y acciones de usuario
const { data, refresh } = await useFetch('/api/products', {
key: 'products-list',
lazy: false,
server: true,
});

Idea clave: centralizar flujo de datos en vez de repetir fetch por componente.


Reto 6: Rendimiento y carga de servidor

Problema

  • SSR incrementa CPU e I/O.
  • Bajo carga, TTFB empeora.

Soluciones

  1. Nitro cache
  2. Optimizar queries a DB
  3. Dividir SSR/CSR por necesidad SEO
  4. Poner CDN correctamente
export default defineCachedEventHandler(
async () => await getProductsFromDB(),
{ maxAge: 60 * 10, swr: true },
);

Idea clave: performance es tema de arquitectura, no solo de componente frontend.


Reto 7: Error handling y 404

Problema

  • IDs dinámicos invalidos.
  • Sin semántica 404 correcta, SEO indexa páginas inválidas.

Solución

if (!product.value) {
throw createError({ statusCode: 404, statusMessage: 'Product not found' });
}

Adicional:

  • error.vue para UX de error clara
  • En error page usar noindex, nofollow

Idea clave: status HTTP, UX y SEO deben ser consistentes.


Reto 8: APIs solo de navegador

Problema

  • En SSR no existe window ni document.
  • Acceso directo rompe en runtime.

Solución

const width = ref<number | null>(null);

onMounted(() => {
width.value = window.innerWidth;
});

O con guarda:

if (process.client) {
localStorage.setItem('theme', 'dark');
}

Idea clave: APIs de navegador solo en fases cliente bien acotadas.


Reto 9: Memory leak en servidor

Problema

  • Proceso Node de larga vida crece en memoria.
  • Causas: estado global mutable, timers/listeners sin limpieza.

Soluciones

  1. Evitar estado global por request
  2. Limpiar listeners/intervals
  3. Observar con heap snapshots y process.memoryUsage()
setInterval(() => {
const mem = process.memoryUsage();
console.log('rss', mem.rss);
}, 60_000);

Idea clave: un leak en SSR es riesgo operativo y también de seguridad.


Reto 10: Scripts de ads y tracking

Problema

  • Scripts de terceros bloquean main thread o rompen hydration.
  • CLS/FID/INP empeoran.

Solución

  • Cargar scripts de forma asíncrona y tardia
  • Reservar espacio para ads para evitar layout shift
  • No depender de tracking para UI crítica
useHead({
script: [
{ src: 'https://example.com/tracker.js', async: true, tagPosition: 'bodyClose' },
],
});

Idea clave: monetizacion no puede degradar estabilidad de rendering.


Reto 11: Arquitectura de despliegue (SSR vs SPA)

Problema

  • SPA se despliega como estático y es simple.
  • SSR necesita capa de computo, observabilidad y gestión de procesos.

Comparación

AspectoSPA (Static)SSR (Node/Edge)
InfraestructuraStorage + CDNCompute + CDN
OperaciónMuy simpleComplejidad media
CostoBajoMás alto por tiempo de computo
MonitoreoMínimoLogs, metrics, memory, cold start

Recomendaciones

  1. PM2 o containers para estabilidad
  2. CDN y Cache-Control bien configurados
  3. Staging con pruebas de carga antes de produccion
  4. Definir error budget y alerting

Idea clave: SSR no es solo render; también es arquitectura operativa.


Resumen para entrevista

Respuesta posible (30-45 segundos):

En SSR suelo dividir los riesgos en cuatro grupos: rendering determinista para evitar hydration mismatch, separación estricta entre configuración de servidor y cliente, optimización de performance con deduplication/cache/splitting, y operación robusta con manejo de errores, monitoreo de memoria y arquitectura de despliegue adecuada.

Checklist:

  • ✅ Mencionar un problema concreto con causa
  • ✅ Explicar contramedidas técnicas
  • ✅ Conectar impacto en SEO/performance/operación
  • ✅ Cerrar con contexto real de proyecto