[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:
- Experiencia real: si implementaste SSR en un entorno real.
- Método de resolución: cómo detectas causa raiz y priorizas.
- Profundidad técnica: rendering, hydration, cache, despliegue.
- 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.envcomplica 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
- Cargar libreria solo en cliente (plugin
.client.ts) - Import dinámico en contexto cliente
- 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
- Nitro cache
- Optimizar queries a DB
- Dividir SSR/CSR por necesidad SEO
- 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.vuepara 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
windownidocument. - 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
- Evitar estado global por request
- Limpiar listeners/intervals
- 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
| Aspecto | SPA (Static) | SSR (Node/Edge) |
|---|---|---|
| Infraestructura | Storage + CDN | Compute + CDN |
| Operación | Muy simple | Complejidad media |
| Costo | Bajo | Más alto por tiempo de computo |
| Monitoreo | Mínimo | Logs, metrics, memory, cold start |
Recomendaciones
- PM2 o containers para estabilidad
- CDN y Cache-Control bien configurados
- Staging con pruebas de carga antes de produccion
- 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