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


Solo Static (HTML)

EJS

¿Puede mostrar datos de la DB?

❌ No

✅ Sí

¿Puede mostrar info del usuario?

❌ No

✅ Sí

¿Puede repetir elementos con bucles?

❌ No

✅ Sí

Velocidad

Más rápida

Muy rápida

Complejidad

Simple

Sencillo


 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

Código

Qué hace

<%= variable %>

Muestra texto escapado (seguro)

<%- html %>

Muestra HTML sin escapar

<% codigo %>

Ejecuta JavaScript (sin mostrar)

<%# comentario %>

Comentario de EJS

<%- include('archivo') %>

Incluye otra plantilla

✅ VENTAJAS DE USAR EJS

  1. Reutilización con include

  2. Lógica dentro del HTML (bucles, condicionales)

  3. Variables pasadas desde el servidor

  4. 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:

Característica

EJS (Node.js)

Blade (Laravel)

Extensión

.ejs

.blade.php

Sintaxis

<%= variable %>

{{ $variable }}

Lógica

<% if (...) { %>

@if (...)

Base

JavaScript

PHP


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:

  1. PHP nació como HTML con PHP incrustado (ya tenía cierta capacidad)

  2. JavaScript en backend es más nuevo (antes solo frontend)

  3. Mucha gente empezó con Laravel y no conoce EJS

Tabla real (ambos SÍ pueden)

Capacidad

EJS

Blade

Mostrar datos diferentes por usuario

✅ Sí

✅ Sí

Conectar con base de datos

✅ Sí

✅ Sí

Personalizar según login

✅ Sí

✅ Sí

Hacer bucles y condiciones

✅ Sí

✅ Sí

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

Entradas más populares de este blog

Cómo Iniciar un Proyecto Node.js

6-Middleware?

5-Express--Curso de Node.js [ #05 Introducción a Express.js ]