En la primera mitad de este artículo, configuramos una pila de desarrollo web y creamos una aplicación de ejemplo simple usando Bun, HTMX, Elysia y MongoDB. Aquí, continuaremos explorando nuestra nueva pila mientras limpiamos y abstraemos la capa de acceso a datos de la aplicación de ejemplo y agregamos interacciones HTMX más complejas. También agregaremos otro componente a la pila tecnológica: Pug, un popular motor de plantillas JavaScript que funciona bien con HTMX y ayuda a configurar las interacciones DOM. La aplicación de ejemplo Nuestra aplicación de ejemplo actualmente consta de un formulario y una tabla. El formulario permite a los usuarios ingresar citas junto con sus autores, que luego se pueden buscar y mostrar utilizando la interfaz de usuario de la aplicación. Agregué un poco de CSS a la interfaz para que parezca más moderna que lo que dejamos en la Parte 1: IDGHaquí está el código de interfaz para la interfaz actualizada:





    Estamos usando HTMX para impulsar el proceso de envío del formulario y carga de datos en la tabla. También limpié el back-end de la aplicación para que la conectividad de la base de datos ahora sea compartida. Aquí está esa parte de src/index.ts: import { Elysia } from «elysia»; importar { staticPlugin } desde ‘@elysiajs/static’; const {MongoClient} = require(‘mongodb’); // Detalles de conexión a la base de datos const url = «mongodb://127.0.0.1:27017/quote?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.8.0»; const dbName = «cita»; const collectionName = «comillas»; let client = new MongoClient(url, { useUnifiedTopology: true }); // Conectarse a la base de datos (llamada solo una vez) async function connectToDatabase() { try { await client.connect(); } captura (error) { consola.error(error); error de lanzamiento; // Vuelve a generar el error para indicar un error de conexión } return { client, collection: client.db(dbName).collection(collectionName) }; } // Cerrar la conexión de la base de datos función asíncrona closeDatabaseConnection(client) { await client.close(); } Lo que estamos haciendo aquí es definir la URL de la base de datos como la dirección de host local predeterminada de MongoDB, junto con una base de datos y un nombre de colección. Luego, usamos una función asíncrona, connectToDatabase(), para conectar el cliente y devolverlo conectado a la colección. Luego, nuestro código puede llamar a este método siempre que necesite acceder a la base de datos, y cuando esté hecho, puede llamar a client.close(). Usando la conexión de la base de datos. Veamos cómo los puntos finales de nuestro servidor usarán este soporte de base de datos. Para abreviar, solo estoy mostrando el punto final /quotes que controla la tabla: // Cerrar la conexión de la base de datos función asíncrona closeDatabaseConnection(client) { await client.close(); } función asíncrona getAllQuotes(colección) { intentar { cotizaciones constantes = esperar colección.find().toArray(); // Construye la estructura de la tabla HTML let html=»

    «; html += ‘

    ‘; for (comilla constante de comillas) { html += `

    `; }html+=’

    Cita Autor
    ${quote.quote} ${quote.autor}

    ‘; devolver html; } catch (error) { console.error(«Error al obtener comillas», error); error de lanzamiento; // Vuelva a generar el error para un manejo adecuado } } // Lógica de la aplicación principal const app = new Elysia() .get(«https://www.infoworld.com/», () => «Hello Elysia») . get(«/quotes», async () => { intentar { const { cliente, colección } = esperar connectToDatabase(); const quotes = esperar getAllQuotes(colección); esperar closeDatabaseConnection(cliente); devolver comillas; } catch (error) { console.error(error); return «Error al obtener comillas»; } }) .use(staticPlugin()) .listen(3000); console.log(` Elysia se está ejecutando en ${app.server?.hostname}:${app.server?.port}` ); Esto nos proporciona un punto final GET back-end /quotes al que podemos llamar para obtener los datos de las cotizaciones. El punto final llama al método getAllQuotes(), que utiliza la colección de connectToDatabase() para obtener la matriz de citas y autores. Luego genera el HTMX para las filas. Finalmente, enviamos una respuesta que contiene las filas como HTMX y las filas se insertan en la tabla. Agregue el motor de plantillas Pug. Crear manualmente la fila HTMX puede causar frustración y errores. Un motor de plantillas nos permite definir la estructura HTMX en un archivo eterno con una sintaxis limpia. El motor de plantillas HTML más popular para JavaScript es Pug. Usarlo hará que la creación de vistas en el servidor sea mucho más fácil y escalable que insertarlas en el código JavaScript. La idea básica es tomar nuestros objetos de datos y pasarlos a la plantilla, que aplica los datos y genera HTML. La diferencia aquí es que estamos generando HTML en lugar de HTML. Podemos hacer esto porque HTMX es esencialmente HTML con extensiones. Para comenzar, agregue la biblioteca Pug al proyecto con: $ bun add pug. Cuando se complete, cree un nuevo directorio en la raíz del proyecto llamado /views: ($ mkdir vistas), luego agregue un nuevo archivo llamado quotes.pug: doctype html h1 Cotizaciones tabla thead tr th Cita th Autor th Acciones tbody cada cita entre comillas tr(id=`quote-${quote._id}`) td #{quote .quote} td #{quote.author} td button(hx-delete=`/quotes/${quote._id}` hx-trigger=»click» hx-swap=»tr más cercano» hx-confirm=»¿Estás ¿seguro?») Eliminar #{quote._id} Pug usa sangría para manejar elementos anidados. Los atributos se mantienen entre paréntesis. El texto sin formato, como la palabra Eliminar, se proporciona tal cual. Todo esto nos brinda una forma compacta de describir HTML y/o HTMX. Consulte la página de inicio de Pug para obtener más información sobre su sintaxis. Observe que dentro de una cadena, necesitamos usar ${}. La sintaxis #{} le permite hacer referencia a cualquier objeto de datos que se haya inyectado en la plantilla. Esto es similar a la interpolación de tokens en un marco como React. La idea básica es definir la estructura HTML/HTMX general y luego proporcionar variables a la plantilla a las que se hace referencia con #{} y ${}. Proporcionamos las variables nuevamente en el punto final del servidor /quotes, que usa getAllQuotes(): import pug de ‘pug’; //… función asíncrona getAllQuotes(colección) { intentar { cotizaciones constantes = esperar colección.find().toArray(); // Representa la plantilla de Pug con las comillas obtenidas const html = pug.compileFile(‘views/quotes.pug’)({ quotes }); devolver html; } catch (error) { console.error(«Error al obtener comillas», error); error de lanzamiento; // Vuelve a generar el error para un manejo adecuado } } Entonces, obtenemos las citas de la base de datos, luego compilamos la plantilla de Pug y pasamos las citas. Luego, Pug hace el trabajo de unir el HTML y los datos. El flujo general es: La solicitud llega a GET /quotes. Las cotizaciones se obtienen de MongoDB. La plantilla Pug recibe las cotizaciones. La plantilla Pug representa las citas como HTML y/o HTMX. El HTML y/o HTMX completado se envía como respuesta. La pantalla resultante se parece a esta: Interacciones IDGDOM: Eliminar una fila. Ahora necesitamos que nuestro botón Eliminar funcione. Simplemente emitir una solicitud de eliminación y manejarla en el servidor y la base de datos es fácil de hacer con lo que ya hemos visto, pero ¿qué pasa con la actualización de la tabla para reflejar el cambio? Hay varias maneras de abordar la actualización. Podríamos simplemente actualizar toda la tabla o podríamos usar JavaScript o HTMX para eliminar la fila de la tabla. Idealmente, nos gustaría usar la última opción y mantener todo como HTMX. En nuestra plantilla views/quotes.pug, podemos usar HTMX puro para eliminar la fila: tbody(hx-target=»closest tr» hx-swap= «outerHTML») cada cita entre comillas tr(id=`quote-${quote._id}`) td #{quote.quote} td #{quote.author} td button(hx-delete=`/quotes/${ quote._id}` hx-trigger=»click» hx-confirm=»¿Estás seguro?») Eliminar Las partes esenciales aquí son hx-target=”closest tr” y hx-swap=”outerHTML” en el tbody. (Hx-confirm le permite proporcionar un cuadro de diálogo de confirmación). Hx-target dice que se reemplace el tr más cercano al elemento desencadenante (el botón) con la respuesta. outHTML en hx-swap garantiza que eliminemos todo el elemento de fila de la tabla, no solo su contenido. En el lado del servidor, devolvemos un éxito (HTTP 200) con un cuerpo vacío, por lo que HTMX simplemente eliminará la fila: async function deleteQuote(collection, quoteId) { try { const result = await collection.deleteOne({ _id: new ObjectId (quoteId) }); if (resultado.deletedCount === 1) { return «»; } else { throw new Error( «Cita no encontrada»); } } catch (error) { console.error(«Error al eliminar la cita», error); error de lanzamiento; // Vuelve a generar el error para un manejo adecuado } } Aquí, apenas estamos comenzando a entrar en interacciones DOM más complicadas. HTMX también puede agregar efectos de transición simples a los intercambios en un escenario de eliminación de filas como el nuestro. Puede ver un ejemplo en la página de inicio de HTMX. Conclusión Aunque este tutorial de dos partes incorpora tecnologías más nuevas como Bun y Elysia, el componente más notable es HTMX. Realmente cambia la forma en que funciona una aplicación en comparación con las API JSON convencionales. Cuando se combina con un motor de plantillas como Pug y una base de datos como MongoDB, el trabajo de generar UI y manejar solicitudes es sencillo. A medida que una aplicación crece en tamaño, las funciones de Pug, como la herencia de plantillas, también resultan útiles. Para las interacciones DOM, HTMX ofrece una funcionalidad flexible lista para usar a través de hx-swap y hx-target. Para casos de uso más complicados, siempre puedes recurrir a JavaScript. En general, toda esta pila funciona bien en conjunto. También puede apreciar la velocidad de Bun cada vez que necesite ingresar a la línea de comando para hacer algo como agregar una dependencia. Puede encontrar el código de este tutorial en mi repositorio de GitHub. Copyright © 2024 IDG Communications, Inc.