13-Web de Lista de Tareas con Node.js, Express, EJS y MySQL

 Inicializar el proyecto

bash

npm init --yes

Express - El framework web

bash

npm install express

Morgan - Logger para desarrollo

bash

npm install morgan

Motor de plantillas

bash

npm install ejs


npm install


npm start

Métodos para Iniciar el Proyecto

a) npm run dev (Recomendado para desarrollo)

bash

npm run dev

  • Cómo funciona: Ejecuta el script "dev" definido en tu package.json

  • Requisito: Debes tener Nodemon instalado y configurado en package.json:

  • json

"scripts": {

  "dev": "nodemon app.js"

  • }

c) npm start (Para producción)

bash

npm start

  • Configuración típica:

  • json

"scripts": {

  "start": "node app.js"

}


Aplicación Web de Lista de Tareas con Node.js, Express, EJS y MySQL

Voy a guiarte paso a paso para crear una aplicación básica de lista de tareas con las tecnologías que mencionaste. Primero, entenderemos cada componente y luego construiremos el proyecto.

Componentes principales

  1. Express: Framework web para Node.js que simplifica la creación de aplicaciones web y APIs.

  2. Router: Módulo de Express que nos permite organizar las rutas en archivos separados.

  3. EJS: Motor de plantillas que nos permite generar HTML dinámico.

  4. express.static: Middleware de Express para servir archivos estáticos (CSS, JS, imágenes).

  5. MySQL: Base de datos relacional donde almacenaremos nuestras tareas.

Estructura del proyecto

Crearemos exactamente la estructura que mencionaste:

text
Copy
Download
mi-app/
├── controllers/
│   └── tareasController.js
├── public/
│   ├── css/
│   │   └── style.css
│   └── js/
│       └── app.js
├── router/
│   └── tareas.js
├── views/
│   ├── index.ejs
│   └── partials/
│       ├── header.ejs
│       └── footer.ejs
├── app.js
└── package.json

Paso 1: Configuración inicial

Primero, crea la estructura de directorios y luego ejecuta:

bash
Copy
Download
npm init -y
npm install express ejs mysql2

Paso 2: Configuración de MySQL

Crea una base de datos y una tabla para las tareas:

sql
Copy
Download
CREATE DATABASE lista_tareas;
USE lista_tareas;

CREATE TABLE tareas (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(255) NOT NULL,
    creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Paso 3: Archivo principal (app.js)

javascript
Copy
Download
const express = require('express');
const path = require('path');
const app = express();

// Configuración de EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// Middleware para archivos estáticos
app.use(express.static(path.join(__dirname, 'public')));

// Middleware para parsear datos del formulario
app.use(express.urlencoded({ extended: true }));

// Rutas
const tareasRouter = require('./router/tareas');
app.use('/', tareasRouter);

// Puerto
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Servidor corriendo en http://localhost:${PORT}`);
});

Paso 4: Controlador (controllers/tareasController.js)

javascript
Copy
Download
const mysql = require('mysql2/promise');

// Configuración de la conexión a MySQL
const pool = mysql.createPool({
    host: 'localhost',
    user: 'root', // Cambia por tu usuario
    password: '', // Cambia por tu contraseña
    database: 'lista_tareas',
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
});

// Obtener todas las tareas
exports.obtenerTareas = async () => {
    const [rows] = await pool.query('SELECT * FROM tareas ORDER BY creado_en DESC');
    return rows;
};

// Agregar nueva tarea
exports.agregarTarea = async (nombreTarea) => {
    await pool.query('INSERT INTO tareas (nombre) VALUES (?)', [nombreTarea]);
};

// Eliminar tarea
exports.eliminarTarea = async (id) => {
    await pool.query('DELETE FROM tareas WHERE id = ?', [id]);
};

Paso 5: Router (router/tareas.js)

javascript
Copy
Download
const express = require('express');
const router = express.Router();
const tareasController = require('../controllers/tareasController');

// Ruta principal - muestra todas las tareas
router.get('/', async (req, res) => {
    try {
        const tareas = await tareasController.obtenerTareas();
        res.render('index', { tareas });
    } catch (error) {
        console.error(error);
        res.status(500).send('Error al cargar las tareas');
    }
});

// Ruta para agregar tarea
router.post('/agregar', async (req, res) => {
    try {
        const { nombre } = req.body;
        if (nombre && nombre.trim() !== '') {
            await tareasController.agregarTarea(nombre.trim());
        }
        res.redirect('/');
    } catch (error) {
        console.error(error);
        res.status(500).send('Error al agregar la tarea');
    }
});

// Ruta para eliminar tarea
router.post('/eliminar/:id', async (req, res) => {
    try {
        const { id } = req.params;
        await tareasController.eliminarTarea(id);
        res.redirect('/');
    } catch (error) {
        console.error(error);
        res.status(500).send('Error al eliminar la tarea');
    }
});

module.exports = router;

Paso 6: Vistas (views/)

views/partials/header.ejs

html
Copy
Download
Run
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lista de Tareas</title>
    <link rel="stylesheet" href="/css/style.css">
</head>
<body>
    <div class="container">
        <h1>Lista de Tareas</h1>

views/partials/footer.ejs

html
Copy
Download
Run
    </div>
    <script src="/js/app.js"></script>
</body>
</html>

views/index.ejs

html
Copy
Download
Run
<%- include('partials/header') %>

        <form action="/agregar" method="POST" class="form-agregar">
            <input type="text" name="nombre" placeholder="Nueva tarea..." required>
            <button type="submit">Agregar</button>
        </form>

        <ul class="lista-tareas">
            <% tareas.forEach(tarea => { %>
                <li>
                    <span><%= tarea.nombre %></span>
                    <form action="/eliminar/<%= tarea.id %>" method="POST" class="form-eliminar">
                        <button type="submit">×</button>
                    </form>
                </li>
            <% }); %>
        </ul>

<%- include('partials/footer') %>

Paso 7: Archivos estáticos (public/)

public/css/style.css

css
Copy
Download
body {
    font-family: Arial, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 20px;
    background-color: #f4f4f4;
}

.container {
    max-width: 600px;
    margin: 0 auto;
    background: #fff;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
    text-align: center;
    color: #333;
}

.form-agregar {
    display: flex;
    margin-bottom: 20px;
}

.form-agregar input {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px 0 0 4px;
}

.form-agregar button {
    padding: 10px 20px;
    background: #5cb85c;
    color: white;
    border: none;
    border-radius: 0 4px 4px 0;
    cursor: pointer;
}

.form-agregar button:hover {
    background: #4cae4c;
}

.lista-tareas {
    list-style: none;
    padding: 0;
}

.lista-tareas li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background: #f9f9f9;
    margin-bottom: 5px;
    border-radius: 4px;
}

.form-eliminar button {
    background: #d9534f;
    color: white;
    border: none;
    border-radius: 50%;
    width: 25px;
    height: 25px;
    cursor: pointer;
}

.form-eliminar button:hover {
    background: #c9302c;
}

public/js/app.js

javascript
Copy
Download
// Aquí puedes agregar funcionalidad JavaScript si es necesario
console.log('Aplicación de lista de tareas cargada');

Explicación de cada componente

  1. Express:

    • Framework minimalista que nos permite crear rutas, middlewares y manejar peticiones HTTP.

    • Configurado en app.js con const app = express().

  2. Router:

    • Nos permite modularizar las rutas en archivos separados.

    • En router/tareas.js definimos todas las rutas relacionadas con tareas.

    • Luego las importamos en app.js con app.use('/', tareasRouter).

  3. EJS (Motor de plantillas):

    • Permite crear HTML dinámico con sintaxis similar a HTML.

    • Configurado en app.js con app.set('view engine', 'ejs').

    • Las plantillas están en la carpeta views/ con extensión .ejs.

    • Usamos <%= %> para imprimir variables y <% %> para lógica JavaScript.

  4. express.static:

    • Middleware para servir archivos estáticos (CSS, JS, imágenes).

    • Configurado en app.js con app.use(express.static(...)).

    • Los archivos en public/ son accesibles directamente desde la raíz (ej. /css/style.css).

  5. MySQL:

    • Usamos el paquete mysql2 para conectarnos a la base de datos.

    • La configuración está en controllers/tareasController.js.

    • Creamos un pool de conexiones para manejar múltiples solicitudes eficientemente.

Cómo ejecutar la aplicación

  1. Asegúrate de tener MySQL instalado y la base de datos creada.

  2. Ejecuta node app.js en la terminal.

  3. Abre tu navegador en http://localhost:3000.

Funcionalidades

  • Ver lista de tareas (GET /)

  • Agregar nueva tarea (POST /agregar)

  • Eliminar tarea (POST /eliminar/:id)

Esta aplicación sigue una estructura MVC (Modelo-Vista-Controlador) básica:

  • Modelo: La interacción con la base de datos (en el controlador en este caso).

  • Vista: Las plantillas EJS en la carpeta views/.

  • Controlador: La lógica de manejo de peticiones en controllers/.

Puedes expandir esta aplicación agregando más funcionalidades como editar tareas, marcar como completadas, autenticación de usuarios, etc

Comentarios

Entradas más populares de este blog

9-Nuestra Primera Plantilla con EJS

6-Middleware?

Cómo Iniciar un Proyecto Node.js