luis Viera
Yo te acompaño con otro comentario para que no estes solito :D
Renderizar HTML desde el servidor de forma estática funciona para empezar, pero se queda corto cuando necesitas inyectar contenido variable. Aquí aprendes a construir una función template en TypeScript que recibe HTML como parámetro y lo devuelve interpolado, un paso clave antes de renderizar una aplicación de React desde el servidor.
¿Por qué necesitas un template HTML dinámico en el servidor?
En la implementación previa, el HTML estaba hardcodeado dentro de la respuesta del servidor. Eso impide cambiar el contenido según la ruta, el usuario o cualquier otra variable. Un template como función resuelve esa limitación porque te permite enviar un documento completo y, al mismo tiempo, decidir en tiempo de ejecución qué va dentro del body.
Piénsalo así: el servidor siempre entrega la estructura del documento (head, meta, lang, div root), pero el contenido interno cambia con cada request.
¿Qué es un template literal en TypeScript? Es una cadena de texto delimitada por backticks que permite interpolar variables y expresiones usando
${}. Sirve para construir HTML dinámico sin concatenar strings.
¿Cómo se estructura la función template en TypeScript?
La idea es crear una carpeta Render y dentro un archivo template.ts que exporte una función. Esa función recibe un parámetro html tipado como string y devuelve un string con el documento HTML completo [01:50].
El flujo concreto se ve así:
Render en la raíz del proyecto.template.ts con export const template.public hacia el return de la función.string.El uso de TypeScript aquí no es decorativo. Al tipar el parámetro como string, evitas que alguien pase un objeto o un número por error y rompa el render. Cuando el editor marca que la función retorna any, lo corriges declarando explícitamente : string en la firma [02:30].
¿Cómo se interpola el HTML dentro del template?
Dentro del body del documento, donde antes había un h1 estático que decía Enviado desde el servidor, colocas ${html}. Esa interpolación reemplaza el contenido fijo por el string que reciba la función [04:20].
ts export const template = (html: string): string => { return `<!DOCTYPE html>
<html lang="es"> <head><title>App</title></head> <body> <div id="app">${html}</div> </body> </html>`; };El div id="app" es importante porque más adelante será el punto de montaje de React.
¿Cómo se consume el template desde el servidor?
En el index del servidor importas la función con import { template } from './Render/template' y la ejecutas pasándole el HTML que quieras renderizar. El autocompletado del editor te confirma que la importación está correcta.
Para probarlo, puedes inyectar contenido basado en la URL del request:
ts
template(<h1>Hola desde la ruta ${request.url}</h1>);
Al recargar el navegador, el h1 cambia según la ruta visitada. Si inspeccionas el DOM, encuentras tanto el contenido dinámico como el div id="app" listo para hidratarse [05:40].
¿Por qué hay que recargar el cliente aunque el servidor ya tenga la respuesta lista? Porque el HTML completo viaja en cada respuesta del servidor. El navegador necesita pedirlo de nuevo para ver los cambios; no hay hot reload sin configuración adicional.
¿Qué detalles del documento conviene revisar?
Un descuido común es dejar el atributo lang en inglés cuando la aplicación está en español. Cambiar lang="en" por lang="es" mejora accesibilidad y SEO, y es el tipo de ajuste que ahora puedes hacer una sola vez en el template [06:30].
Otros puntos a verificar en el documento base:
DOCTYPE declarado correctamente.title que verá el usuario en la pestaña.div con id="app" donde React montará la aplicación.lang alineado al idioma del contenido.¿Qué limitación queda pendiente con archivos estáticos?
El template ya envía HTML dinámico, pero todavía no resuelve cómo servir archivos estáticos como el favicon o el app.js. Esos archivos viven del lado del cliente, dentro de assets, y necesitan ser procesados y compilados antes de que el navegador pueda consumirlos.
Ese paso obliga a configurar la compilación de la aplicación de React para que el servidor pueda exponer los bundles generados. Es el siguiente eslabón natural: tener un template dinámico que además sirva los recursos que el cliente requiere para hidratar la app.
¿Cómo estás organizando tu carpeta Render en tus proyectos? Cuéntame en los comentarios qué patrones te han funcionado para separar la lógica de servidor del rendering.
luis Viera
Yo te acompaño con otro comentario para que no estes solito :D
Xavier Flores
ya casí terminando la ruta con React
Gonzalo Gutiérrez Castillo
Yo igual
Marvin Manuel Menchu Menchu
Company_adminYo los acompaño a terminar la ruta de Frontend con React.js
Raycris Maldonado
Somos leyendas 😂
Angel Bernechea
Aquí otro mas que se reporta XD
Leonardo Fonseca
Uno más por aquí 🙂
Roberto Cruz
Donde está todo el mundo? :c
Michell García Ibarra
Para aquellos que usan express 5+, el wildcard '*' como se muestra en la clase no funciona, pueden remplazarlo por '/{*splat}', quedando de la siguiente forma:
app.get('/{*splat}', (req: Request, res: Response) => { res.send(`<h1>Hola mundo con ruta: ${req.url}</h1>`); });
Diego Reyes Cabrera
Los comentarios:
David Rangel
Algo que me pasa desde la clase pasada es que la primera iteración para validar que se cambiaba el hola mundo con el console.log funcionó bien pero después la inyectar el h1, por más modifico el h1, corro y apago el proyecto y lo abro en otros navegadores persiste el mismo h1 sin cambios.
Este es parte de mi código:
app.get('/{\*splat}', (req: Request, res: Response) => { res.send(`<h1> Hola mundo : ${req.url} </h1>`); });
David Rangel
David Rangel
Así se ve en navegador:
Este problema no me pasa si me muevo al puerto 3600.
import express, { Express, Request, Response } from 'express'; import { config } from './config'; const app: Express = express(); app.use((req: Request, res: Response, next: any) => { res.setHeader( 'Content-Security-Policy', "default-src 'self'; " + "script-src 'self' 'unsafe-inline'; " + "connect-src 'self' http://localhost:* ws://localhost:*;", ); next(); }); app.get('/{\*splat}', (req: Request, res: Response) => { res.send(`<h1> Hola mundo : ${req.url} </h1>`); }); app.use((err: any, res: Response) => { console.error('🌊 Alerta de naufragio:', err.message); res.status(500).send('Algo salió mal en la bodega del barco.'); }); app.listen(3600, () => { console.log(`Listenting in http://localhost:${3600}`); });