3: Rutas, Partials y Bootstrap

馃幆 Objetivo de esta parte

Aprender a organizar un proyecto Node.js/Express usando:

  • Carpeta routes/ para separar las rutas del servidor

  • Carpeta views/partials/ para reutilizar componentes HTML

  • Bootstrap para estilos r谩pidos

  • Estructura profesional de archivos


1️⃣ Estructura final del proyecto

Basado en tus im谩genes, esta es la estructura que lograremos:

text
ejs-node/
├── node_modules/
├── routes/
│   └── index.js
├── views/
│   ├── partials/
│   │   ├── head.ejs
│   │   └── header.ejs
│   ├── index.ejs
│   └── new-entry.ejs
├── app.js
├── package.json
└── package-lock.json

2️⃣ Crear la carpeta routes y el archivo index.js

Paso 1: Crear la carpeta routes

bash
mkdir routes

Paso 2: Crear routes/index.js

javascript
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
    res.render('index', {
        title: 'Inicio'
    });
});

router.get('/new-entry', (req, res) => {
    res.render('new-entry', {
        title: 'Nueva Entrada'
    });
});

module.exports = router;

馃摉 Explicaci贸n del c贸digo:

ElementoFunci贸n
express.Router()Crea un manejador de rutas independiente
router.get()Define rutas dentro de este m贸dulo
module.exportsExporta el router para usarlo en app.js

3️⃣ Modificar app.js para usar las rutas

Actualiza tu app.js para importar y usar el router:

javascript
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const bodyParser = require('body-parser');

const app = express();

// Configuraciones
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// Middlewares
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Rutas - IMPORTANTE: deben ir despu茅s de los middlewares
app.use('/', require('./routes/index'));

// Iniciar servidor
app.listen(app.get('port'), () => {
    console.log(`servidor en puerto ${app.get('port')}`);
});

馃攽 Clave: app.use('/', require('./routes/index')) le dice a Express que use todas las rutas definidas en routes/index.js para las URLs que empiecen con /.


4️⃣ Crear la carpeta partials y sus archivos

Crear la carpeta:

bash
mkdir views/partials

Crear views/partials/head.ejs

Este archivo contendr谩 todo lo relacionado con <head> y Bootstrap:

html
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style>
    body {
        padding-top: 70px;
    }
</style>

Crear views/partials/header.ejs

Este es el men煤 de navegaci贸n:

html
<nav class="navbar navbar-default navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">Express GuestBook</a>
        </div>
        <ul class="nav navbar-nav">
            <li><a href="/">Inicio</a></li>
            <li><a href="/new-entry">Nueva entrada</a></li>
        </ul>
    </div>
</nav>

5️⃣ Crear las vistas principales

Crear views/index.ejs

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title><%= title %> | GuestBook</title>
    <% include partials/head %>
</head>
<body class="container">
    <% include partials/header %>
    
    <div class="jumbotron">
        <h1>Libro de Visitas</h1>
        <p>Bienvenido a nuestro libro de visitas. Deja tu mensaje y lee lo que otros han escrito.</p>
        <a href="/new-entry" class="btn btn-primary btn-lg">Escribir mensaje</a>
    </div>
    
    <h2>Mensajes recientes</h2>
    <div class="alert alert-info">
        Pr贸ximamente: lista de mensajes
    </div>
</body>
</html>

Crear views/new-entry.ejs

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title><%= title %> | GuestBook</title>
    <% include partials/head %>
</head>
<body class="container">
    <% include partials/header %>
    
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3>Escribe un mensaje</h3>
                </div>
                <div class="panel-body">
                    <form action="/add-entry" method="POST">
                        <div class="form-group">
                            <label for="title">T铆tulo</label>
                            <input type="text" name="title" id="title" class="form-control" required>
                        </div>
                        <div class="form-group">
                            <label for="message">Mensaje</label>
                            <textarea name="message" id="message" rows="5" class="form-control" required></textarea>
                        </div>
                        <button type="submit" class="btn btn-primary">Guardar mensaje</button>
                        <a href="/" class="btn btn-default">Cancelar</a>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

6️⃣ La sintaxis include en EJS

Observa c贸mo estamos reutilizando c贸digo:

ejs
<% include partials/head %>
<% include partials/header %>

馃摉 Beneficios de los partials:

  • Reutilizaci贸n: Un mismo men煤 en todas las p谩ginas

  • Mantenimiento: Cambias el men煤 una sola vez

  • Organizaci贸n: C贸digo m谩s limpio y ordenado


7️⃣ Probar la aplicaci贸n

Iniciar el servidor:

bash
npm run dev

Verificar las rutas:

  • http://localhost:3000/ → P谩gina de inicio

  • http://localhost:3000/new-entry → Formulario de nueva entrada


8️⃣ Explicaci贸n de las rutas (importante)

En routes/index.js definimos:

RutaM茅todoArchivo renderizadoURL amigable
/GETindex.ejsP谩gina principal
/new-entryGETnew-entry.ejsFormulario

En app.js conectamos el router:

javascript
app.use('/', require('./routes/index'));

Esto significa: "Todas las rutas definidas en routes/index.js ser谩n accesibles desde la ra铆z /".

Si quisieras un prefijo como /api, har铆as:

javascript
app.use('/api', require('./routes/index'));
// Ahora las rutas ser铆an /api/ y /api/new-entry

馃摑 Resumen de lo aprendido

ConceptoC贸digo clave
Router de Expressconst router = express.Router()
Exportar rutasmodule.exports = router
Importar rutasapp.use('/', require('./routes/index'))
Incluir partials<% include partials/header %>
Pasar t铆tulo din谩mico{ title: 'Inicio' } y <%= title %>

馃帹 Bootstrap incluido

Ya tienes Bootstrap funcionando gracias a partials/head.ejs:

  • Estilos profesionales

  • Navbar fijo

  • Sistema de grillas

  • Botones y paneles con estilo


馃殌 Pr贸ximo paso: Recibir datos del formulario (POST)

En la siguiente parte aprenderemos a:

  1. Capturar los datos enviados por el formulario usando body-parser

  2. Almacenar mensajes en un arreglo

  3. Mostrar la lista de mensajes en la p谩gina principal

  4. Redireccionar despu茅s de guardar


馃敡 Nota sobre body-parser (actualizada)

Siguiendo tus im谩genes, mantenemos body-parser. Pero recuerda que en versiones actuales puedes usar:

javascript
// En lugar de:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Puedes usar directamente:
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

Para la pr贸xima parte (formularios POST), necesitaremos urlencoded() para leer los datos del formulario.


✅ Verifica tu estructura

Tu proyecto deber铆a verse as铆 (como en tus im谩genes):

text
ejs-node/
├── node_modules/
├── routes/
│   └── index.js
├── views/
│   ├── partials/
│   │   ├── head.ejs
│   │   └── header.ejs
│   ├── index.ejs
│   └── new-entry.ejs
├── app.js
├── package.json
└── package-lock.json

¿Quieres que contin煤e con la Parte 4 donde procesamos el formulario POST y mostramos los mensajes guardados?

Completar el formulario en new-entry.ejs

Basado en tus im谩genes, este es el formulario completo que debes tener en views/new-entry.ejs:

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title><%= title %></title>
    <% include partials/head %>
</head>
<body class="container">
    <% include partials/header %>
    
    <div class="col-xs-8 col-xs-offset-2">
        <h2 class="text-center">Write a new Entry</h2>
        
        <form method="POST" action="/add-entry">
            <div class="form-group">
                <label for="title">Title:</label>
                <input 
                    type="text" 
                    name="title" 
                    id="title" 
                    class="form-control"
                    placeholder="Enter a new Title"
                    required>
            </div>

            <div class="form-group">
                <label for="body">Entry Text:</label>
                <textarea 
                    class="form-control"
                    id="body"
                    name="body"
                    rows="5"
                    required></textarea>
            </div>

            <div class="form-group">
                <input type="submit" value="Post Entry" class="btn btn-primary">
                <a href="/" class="btn btn-default">Cancel</a>
            </div>
        </form>
    </div>
</body>
</html>

馃摉 Explicaci贸n del formulario:

AtributoValorFunci贸n
methodPOSTEnv铆a datos ocultos (no en la URL)
action/add-entryURL donde se enviar谩n los datos
name="title"-Nombre del campo (lo usaremos en el servidor)
name="body"-Nombre del campo para el mensaje
required-El campo es obligatorio (HTML5)
class="form-control"-Estilo de Bootstrap

Comentarios

Entradas m谩s populares de este blog

C贸mo Iniciar un Proyecto Node.js

9-Nuestra Primera Plantilla con EJS

Lista de tareas-routing y plantillas