3.2Motores de plantillas y servicio de archivos
Lo esencial en 30 segundos
- Lo estático se sirve en una línea : app.use(express.static('public')) entrega CSS, imágenes y JS de cliente desde una carpeta dedicada.
- Lo dinámico se renderiza con un motor : plantillas EJS/Handlebars/Pug + res.render('vista', { datos }) = HTML ensamblado en el servidor (SSR).
- Dos arquitecturas válidas : SSR para contenido y SEO, API JSON + front separado para apps interactivas — los niveles siguientes se inclinan hacia la API.
Mini-caso hilado — Salim publica el catálogo en SSR y luego en API
Salim, desarrollador junior en Argel, debe publicar el catálogo : fichas de producto en HTML para el posicionamiento, más un cuadro de mando interno muy interactivo. Sirve primero el CSS y las imágenes con express.static('public'), configura EJS (app.set('view engine', 'ejs')) y renderiza res.render('produit', { produit }) para las fichas SSR. Para el cuadro de mando, expone los mismos datos en res.json() : el front dedicado consumirá la API. Un solo servidor, dos renderizados según el uso.
Este mismo caso vuelve en el curso, el esquema, el guion y el reto 48h.
1. Archivos estáticos y plantillas
Una app web entrega recursos fijos (CSS, imágenes, JS de cliente, fuentes) : Express los sirve con el middleware nativo express.static() — app.use(express.static('public')) expone toda la carpeta public/ (una petición hacia /style.css devuelve public/style.css). Se agrupan los assets en esa carpeta dedicada.
Para el HTML dinámico, se usa un motor de plantillas : una plantilla (HTML + variables, bucles, condiciones) rellenada con datos. Los corrientes : EJS (JS en etiquetas <% %>, cercano al HTML), Handlebars/hbs (sintaxis {{ }}, depurada), Pug (indentado, conciso). Se configura (app.set('view engine', 'ejs')), se guardan las vistas en views/, se renderiza con res.render('page', { datos }). Es el SSR (Server-Side Rendering) : el servidor construye el HTML completo y lo envía al navegador.
2. SSR o API + front separado : arbitrar según el proyecto
El SSR conviene a los sitios de contenido (escaparates, blogs, comercio electrónico clásico), al SEO (HTML listo, bien indexable) y a la carga inicial rápida. La alternativa moderna : Node expone una API REST en JSON (sección 4-1) consumida por un front separado (React, Vue, Angular) que muestra en el navegador — ideal para las apps interactivas (cuadros de mando, herramientas) y la experiencia fluida sin recarga.
Ambas son válidas : Salim elige SSR para las fichas (contenido, SEO) y API + front para el cuadro de mando (interactividad). Y el SSR no está superado : vuelve con fuerza vía Next.js/Nuxt que combinan renderizado servidor e interactividad. Los niveles siguientes se inclinan hacia el enfoque API/JSON, dominante en Node.
🔎 Ejemplo concreto — Servir luego renderizar, luego exponer en JSON
Salim cubre las tres salidas con el mismo servidor.
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.get('/produits/:id', (req, res) => {
res.render('produit', { produit: { id: req.params.id } });
});
app.get('/api/produits/:id', (req, res) => {
res.json({ id: req.params.id });
});
Lectura : mismo dato, dos renderizados : HTML vía EJS o JSON vía res.json().
Lección : comparar ambos renderizados hace sentir la diferencia SSR frente a API.
Vocabulario de la sección
- Archivos estáticos
- Recursos fijos (CSS, imágenes, JS de cliente, fuentes) servidos tal cual por express.static('public').
Ejemplo sencillo: El style.css de Salim servido desde public/.
Lo que no es: una vista EJS renderizada con datos.
Reflejo: agrupar todos los assets en public/.
- Motor de plantillas
- Herramienta que genera HTML dinámico desde plantillas (variables, bucles, condiciones) : EJS, Handlebars, Pug.
Ejemplo sencillo: La ficha de producto EJS de Salim iterando sobre las reseñas.
Lo que no es: una simple carpeta de archivos fijos.
Reflejo: elegir EJS para empezar, cercano al HTML.
- res.render()
- Método Express que renderiza una vista : res.render('page', { datos }) inyecta los datos en la plantilla de views/.
Ejemplo sencillo: res.render('produit', { produit }) en casa de Salim.
Lo que no es: un envío de JSON en bruto al front.
Reflejo: nombrar la vista como el archivo de views/.
- SSR
- Server-Side Rendering : el servidor genera el HTML completo y lo envía al navegador ; baza de contenido y SEO.
Ejemplo sencillo: Las fichas de catálogo indexables de Salim.
Lo que no es: una SPA que renderiza todo en el navegador.
Reflejo: privilegiar el SSR para las páginas por posicionar.
- API + front separado
- Node expone JSON (API REST) consumido por un front React/Vue/Angular que muestra en el navegador.
Ejemplo sencillo: El cuadro de mando interno alimentado en res.json().
Lo que no es: una plantilla EJS renderizada en el servidor.
Reflejo: reservar esta arquitectura a las apps interactivas.
En la práctica — Servir archivos y generar HTML
- Servid archivos estáticos con app.use(express.static('public')) : colocad un CSS y una imagen en public/ y comprobad que son accesibles.
- Configurad un motor de plantillas (p. ej. EJS : app.set('view engine', 'ejs')) y colocad plantillas en views/.
- Renderizad una vista con datos : res.render('page', { titre: '...', items: [...] }) ; en la plantilla, insertad las variables e iterad sobre una lista.
- Comparad : renderizad el mismo dato en JSON (res.json(data), enfoque API) para percibir la diferencia SSR frente a API + front separado.
Guion listo para decir — justificar SSR frente a API (30 s)
« Las fichas del catálogo salen en SSR con EJS : HTML completo, bueno para el SEO y la primera visualización. El cuadro de mando, muy interactivo, consume el mismo dato en JSON vía nuestra API. Lo estático CSS e imágenes lo sirve express.static desde public. »
Para decir en arbitraje de arquitectura ; mostrar el mismo dato en HTML y luego en JSON.
Modelo copiar-pegar — estático + EJS + JSON
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.get('/produits/:id', (req, res) => {
res.render('produit', { id: req.params.id });
});
app.get('/api/produits/:id', (req, res) => {
res.json({ id: req.params.id });
});
app.listen(3000);
Independiente
Un sitio escaparate basta en SSR + estático : sin front pesado para unas pocas páginas.
Pyme en Argel
Salim renderiza las fichas en EJS para el SEO y guarda la API JSON para la admin interna.
Equipo de producto
Separar views/ (SSR) y /api (JSON) para que dos equipos avancen sin conflicto.
Principiante
Esta semana : un CSS servido en estático y una vista EJS con un bucle sobre tres ítems.
✓ Buenas prácticas
- Servir los assets con express.static (una carpeta public/).
- Elegir la arquitectura según el proyecto (contenido/SEO frente a app interactiva).
- Dominar la API REST (JSON) : enfoque dominante de los niveles siguientes.
✗ Errores frecuentes
- Creer el SSR « superado » (conoce una renovación : Next.js/Nuxt).
- Elegir una SPA para un simple sitio de contenido (complejidad inútil).
- Descuidar el SEO en arquitectura SPA pura.
Puntos clave
- SERVICIO ESTÁTICO : app.use(express.static('public')) sirve los recursos fijos (CSS, imágenes, JS de cliente).
- MOTORES DE PLANTILLAS (EJS, Handlebars, Pug) : HTML dinámico vía res.render('vista', {datos}).
- SSR : el servidor genera el HTML completo — enfoque de los sitios clásicos (contenido, SEO).
- Alternativa moderna muy extendida : Node expone una API REST (JSON) consumida por un FRONT SEPARADO (React/Vue/Angular).
Reto 48h — aplica mañana
Servid 1 CSS en estático y renderizad 1 vista EJS con un bucle sobre 3 ítems.
- Sirvo una carpeta public/ sin dudar.
- Renderizo una vista con res.render().
- Arbitrio SSR frente a API según el proyecto.
Preguntas frecuentes
¿SSR (plantillas) o API + front separado : qué arquitectura elegir?
Ambas son válidas según el proyecto. El SSR conviene a los sitios de contenido (blogs, escaparates, comercio electrónico clásico), cuando el SEO cuenta (HTML entregado listo), para una carga inicial rápida y los sitios poco interactivos (más simple). La API + front separado conviene a las apps interactivas (cuadros de mando, herramientas), a la experiencia fluida sin recarga y a la separación front/back. Salim combina : SSR para las fichas, API para el cuadro de mando.
¿Está superado el renderizado en servidor frente a React?
No, conoce incluso una renovación. Tras la era SSR clásica (plantillas EJS), luego el entusiasmo SPA (todo renderizado en el cliente, con sus límites SEO y de carga inicial), frameworks como Next.js y Nuxt combinan ambos : HTML renderizado servidor (SEO, rapidez) + interactividad cliente (experiencia SPA). El SSR clásico sigue pertinente para muchos sitios por su simplicidad.
¿Qué método Express renderiza una vista con datos?