8.2-Implementando EJS en tu ejercicio de Express
EJS en términos simples
EJS es como tener "HTML con superpoderes" que puede mostrar datos dinámicos.
El problema: Solo HTML estático
Con solo archivos estáticos (tu public/index.html)
html
<!-- Esto está FIJADO, no cambia -->
<h1>Bienvenido Juan Pérez</h1>
<p>Tienes 0 productos en tu carrito</p>
<!-- Para cada usuario tendrías que crear un HTML diferente 😱 -->
Problema: No puedes mostrar información diferente para cada usuario.
La solución: EJS
Con EJS (archivo .ejs)
html
<!-- Este SÍ cambia según cada usuario -->
<h1>Bienvenido <%= nombre %></h1>
<p>Tienes <%= cantidadProductos %> productos en tu carrito</p>
Resultado: El mismo archivo muestra datos diferentes para cada persona.
Ejemplo práctico con tu código
Ahora (solo estático)
javascript
// Tu código actual
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
// El HTML es siempre el mismo, no puede mostrar productos
});
Con EJS
javascript
// Instalar: npm install ejs
// Configurar EJS
app.set('view engine', 'ejs');
// Ahora puedes pasar datos DINÁMICOS
app.get('/', (req, res) => {
res.render('index', {
nombre: 'Carlos',
productos: productos, // Tus productos de la base de datos
totalProductos: productos.length
});
});
Tu archivo views/index.ejs
html
<!DOCTYPE html>
<html>
<head>
<title>Mi Tienda</title>
</head>
<body>
<h1>Bienvenido <%= nombre %></h1>
<h2>Productos disponibles ( <%= totalProductos %> )</h2>
<ul>
<% productos.forEach(producto => { %>
<li>
<%= producto.nombre %> - $<%= producto.precio %>
</li>
<% }) %>
</ul>
<!-- El HTML cambia según los datos que envías -->
</body>
</html>
Comparación directa
Implementando EJS en tu ejercicio de Express
Aquí tienes una explicación clara y sencilla para implementar EJS paso a paso:
1️⃣ INSTALAR EJS
Primero, instala EJS en tu proyecto:
bash
npm install ejs
2️⃣ CONFIGURAR EL MOTOR DE VISTAS
Agrega estas líneas después de crear app y antes de las rutas:
javascript
const express = require('express');
const app = express();
const PORT = 3000;
// ============ CONFIGURACIÓN DE EJS ============
app.set('view engine', 'ejs'); // Configurar EJS como motor de vistas
app.set('views', __dirname + '/views'); // Carpeta donde irán las vistas
3️⃣ CREAR LA CARPETA DE VISTAS
Crea una carpeta llamada views en la raíz de tu proyecto:
text
tu-proyecto/
├── views/ ← Carpeta nueva
├── public/
├── node_modules/
└── server.js
4️⃣ CREAR PLANTILLAS EJS
📄 views/layout.ejs (Plantilla principal)
ejs
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
<%- body %>
</div>
<script src="/js/bootstrap.bundle.min.js"></script>
</body>
</html>
📄 views/index.ejs (Página principal)
ejs
<% include layout.ejs %>
<h1 class="text-center">📦 Gestión de Productos</h1>
<!-- Formulario para agregar productos -->
<div class="card mt-4">
<div class="card-header bg-primary text-white">
<h3>➕ Agregar Nuevo Producto</h3>
</div>
<div class="card-body">
<form action="/productos-formulario" method="POST">
<div class="mb-3">
<label class="form-label">Nombre del producto:</label>
<input type="text" name="nombre" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Precio ($):</label>
<input type="number" name="precio" step="0.01" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">💾 Guardar Producto</button>
</form>
</div>
</div>
<!-- Tabla de productos -->
<div class="card mt-4">
<div class="card-header bg-success text-white">
<h3>📋 Lista de Productos</h3>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Precio</th>
</tr>
</thead>
<tbody>
<% productos.forEach(producto => { %>
<tr>
<td><%= producto.id %></td>
<td><%= producto.nombre %></td>
<td>$<%= producto.precio %></td>
</tr>
<% }) %>
</tbody>
</table>
<% if (productos.length === 0) { %>
<div class="alert alert-warning">No hay productos registrados</div>
<% } %>
</div>
</div>
5️⃣ MODIFICAR LAS RUTAS
Reemplaza la ruta GET / (que usaba res.sendFile) por:
javascript
// Ruta principal con EJS
app.get('/', (req, res) => {
res.render('index', {
title: 'Mi Tienda - Productos',
productos: productos
});
});
MODIFICA también la ruta GET /productos para probar EJS con una vista:
javascript
// Vista para ver todos los productos (versión HTML)
app.get('/productos-vista', (req, res) => {
res.render('productos', {
title: 'Lista de Productos',
productos: productos,
total: productos.length
});
});
CREA la vista views/productos.ejs:
ejs
<% include layout.ejs %>
<h1>📦 Productos Registrados</h1>
<p class="lead">Total de productos: <strong><%= total %></strong></p>
<a href="/" class="btn btn-primary mb-3">← Volver al inicio</a>
<table class="table table-bordered">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Precio</th>
</tr>
</thead>
<tbody>
<% productos.forEach(p => { %>
<tr>
<td><%= p.id %></td>
<td><%= p.nombre %></td>
<td>$<%= p.precio %></td>
</tr>
<% }) %>
</tbody>
</table>
📝 CÓDIGO COMPLETO ACTUALIZADO
javascript
const express = require('express');
const app = express();
const PORT = 3000;
// ============ CONFIGURACIÓN EJS ============
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
// ============ MIDDLEWARE ============
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use('/css', express.static('node_modules/bootstrap/dist/css'));
app.use('/js', express.static('node_modules/bootstrap/dist/js'));
// ============ DATOS ============
let productos = [
{ id: 1, nombre: 'Laptop', precio: 1000 },
{ id: 2, nombre: 'Mouse', precio: 25 },
{ id: 3, nombre: 'Teclado', precio: 50 }
];
// ============ RUTAS CON EJS ============
app.get('/', (req, res) => {
res.render('index', {
title: 'Mi Tienda',
productos: productos
});
});
app.get('/productos-vista', (req, res) => {
res.render('productos', {
title: 'Lista de Productos',
productos: productos,
total: productos.length
});
});
// ============ RUTAS API (JSON) ============
app.get('/productos', (req, res) => {
res.json(productos);
});
app.post('/productos-formulario', (req, res) => {
const { nombre, precio } = req.body;
if (!nombre || !precio) {
return res.status(400).send('Faltan datos');
}
const nuevoProducto = {
id: productos.length + 1,
nombre: nombre,
precio: parseFloat(precio)
};
productos.push(nuevoProducto);
res.redirect('/'); // Redirige a la vista con EJS
});
// Iniciar servidor
app.listen(PORT, () => {
console.log(`🚀 Servidor en http://localhost:${PORT}`);
});
🎯 SINTÁXIS BÁSICA DE EJS
✅ VENTAJAS DE USAR EJS
Reutilización con include
Lógica dentro del HTML (bucles, condicionales)
Variables pasadas desde el servidor
Rápido y fácil de aprender
¡Ya tienes tu servidor con EJS funcionando!
En Laravel, el equivalente a EJS se llama Blade. Es su motor de plantillas "de fábrica".
Aquí te explico la comparación de forma sencilla:
1. La Diferencia Visual (y Conceptual)
En lugar de abrir mil veces <?php ?>, Blade usa el símbolo @ para hacer la lectura más limpia .
Así se ve el código:
blade
<!-- Así se ve un archivo .blade.php -->
<h1>Bienvenido, {{ $nombre }}</h1>
@if($totalProductos > 0)
<p>Tienes {{ $totalProductos }} productos en el carrito.</p>
@foreach($productos as $producto)
<li>{{ $producto->nombre }} - ${{ $producto->precio }}</li>
@endforeach
@else
<p>Tu carrito está vacío.</p>
@endif
¿Ves? Es casi idéntico a EJS, pero cambia <%= por {{ y <% por @ .
2. Blade vs. Static: El mismo problema que con EJS
Pasa exactamente lo mismo que con Express y EJS.
Solo Static (HTML suelto): No puedes mostrar los productos que vienen de la Base de Datos. Todo está escrito a mano y fijo .
Con Blade: Es la herramienta que conecta tu backend (Laravel) con el frontend (HTML).
Ejemplo en tu controlador:
php
// Controlador de Laravel
public function index()
{
$productos = Producto::all(); // Trae datos de la DB
return view('tienda', compact('productos')); // Se los pasas a la vista
}
3. ¿Qué ventajas tiene sobre el Static o el PHP puro?
Blade no solo hace lo mismo que EJS, sino que trae "extras" que ayudan muchísimo :
¡Protege tu web de hackers! (XSS): Cuando pones {{ $texto }}, Blade escapa automáticamente el código HTML. Si un usuario malicioso intenta inyectar <script>, Blade lo desactiva. En HTML estático o PHP suelto, tienes que acordarte de hacerlo manualmente .
Herencia de Layouts: Puedes crear un layout.blade.php principal (con header, footer, menú) y las otras páginas solo "extienden" ese modelo. Evita copiar y pegar código HTML mil veces.
blade
{{-- dashboard.blade.php --}}
@extends('layouts.admin')
@section('content')
<h1>Solo escribo el contenido de aquí</h1>
@endsection
Componentes: Puedes crear piezas de código reutilizables.
blade
{{-- En lugar de copiar un botón 100 veces --}}
<x-boton-primario color="azul">Guardar</x-boton-primario>
¿Dónde guardar los archivos?
Mientras en Express/EJS los guardabas en una carpeta views (o /public si era estático), en Laravel hay una convención fija:
Ruta incorrecta (Estático): /public/index.html -> No se usa para páginas dinámicas.
Ruta correcta (Blade): resources/views/mi-pagina.blade.php .
No es que EJS no pueda y Blade sí. Ambos PUEDEN. La diferencia está en el lenguaje base que usan.
Explicación sencilla
EJS (Node.js/Express)
javascript
// Puedes mostrar datos diferentes SÍ 👇
app.get('/perfil', (req, res) => {
const usuario = { nombre: 'Ana', edad: 25 };
res.render('perfil', { usuario }); // ✅ Sí se puede
});
Blade (Laravel/PHP)
php
// También puedes mostrar datos diferentes 👇
Route::get('/perfil', function () {
$usuario = ['nombre' => 'Ana', 'edad' => 25];
return view('perfil', compact('usuario')); // ✅ Sí se puede
});
¿Por qué parece que "solo Blade puede"?
Por una razón histórica y práctica:
En PHP (Laravel) tradicional:
php
// SIN Blade, así se hacía ANTES (horrible)
<?php
$nombre = "Ana";
echo "<h1>Bienvenido $nombre</h1>";
echo "<ul>";
foreach($productos as $p) {
echo "<li>$p->nombre</li>";
}
echo "</ul>";
?>
Blade nació para ESCONDER ese PHP feo y hacerlo bonito:
blade
<!-- CON Blade (bonito y limpio) -->
<h1>Bienvenido {{ $nombre }}</h1>
<ul>
@foreach($productos as $p)
<li>{{ $p->nombre }}</li>
@endforeach
</ul>
En Node.js/Express:
javascript
// SIN EJS, así se haría (también horrible)
app.get('/', (req, res) => {
let html = `<h1>Bienvenido ${nombre}</h1><ul>`;
productos.forEach(p => {
html += `<li>${p.nombre}</li>`;
});
html += `</ul>`;
res.send(html); // 😰 Asqueroso
});
EJS hace lo mismo que Blade pero con JavaScript:
ejs
<!-- CON EJS (bonito y limpio) -->
<h1>Bienvenido <%= nombre %></h1>
<ul>
<% productos.forEach(p => { %>
<li><%= p.nombre %></li>
<% }) %>
</ul>
La confusión común
La gente cree que "solo Blade puede" porque:
PHP nació como HTML con PHP incrustado (ya tenía cierta capacidad)
JavaScript en backend es más nuevo (antes solo frontend)
Mucha gente empezó con Laravel y no conoce EJS
Tabla real (ambos SÍ pueden)
Entonces, ¿cuál es la diferencia REAL?
No es si PUEDEN o no, sino CÓMO se escribe:
javascript
// EJS (JavaScript)
<% if (usuario.activo) { %>
<p>Hola <%= usuario.nombre %></p>
<% } %>
php
// Blade (PHP)
@if($usuario->activo)
<p>Hola {{ $usuario->nombre }}</p>
@endif
Conclusión
No necesitas EJS para mostrar datos dinámicos en Express
No necesitas Blade para mostrar datos dinámicos en Laravel
Pero usarlos te ahorra escribir código horrible:
En lugar de concatenar HTML a mano (feo)
Usas plantillas limpias (bonito)
Ambos resuelven el MISMO problema pero con la sintaxis de su lenguaje:
EJS = JavaScript + HTML
Blade = PHP + HTML
¡Ambos son necesarios si no quieres volverte loco creando HTML a mano!
Comentarios
Publicar un comentario