
Este repositorio contiene un HDA basado en HTMX (frontend) y Drogon C ++ Framework (backend).
El objetivo era crear una "aplicación web" receptiva sin usar ninguno de los marcos de JavaScript habituales.
La idea de este proyecto se produjo al leer el excelente libro Hypermedia Systems. En él, los autores hablan sobre formas alternativas para escribir aplicaciones web modern . A diferencia de la mayoría de los otros libros sobre desarrollo web, los autores no confían en ningún marco de JavaScript, sino que vuelven a las raíces de la arquitectura HyperMedia que es the web en sí.
También he escrito un artículo sobre este proyecto y mi motivación general para usar HTMX y C ++.
En lugar de usar JavaScript para superar HTML, una estrategia que básicamente reproduce a los clientes gruesos de los 90Es, los autores usan htmx para aumentarlo . Lo hacen capaz de hacer más sin volver a caer a los trucos inteligentes de JavaScript. Por supuesto, JS no está prohibido y htmx se basa en él para su propio desarrollo, pero JS no es visible ya que no hay necesidad real de ello.
No necesitamos usar JS para reemplazar los controles de hipermedia aparentemente "insuficientes", porque HTMX está aquí para extenderlos. Los hace capaces de hacer más como se define originalmente. Una etiqueta de anclaje ( <a> ), por ejemplo, se puede "actualizar" para que pueda ejecutar post, poner, parche o incluso eliminar solicitudes. Una etiqueta <form> no tiene que ser el único control de hipermedia para enviar datos a través de solicitudes posteriores. ¿Qué tal escribir sus propios controles que pueden hacer exactamente lo mismo? ¿O tal vez <form> s que puede parchear las entradas existentes en el servidor? Lo que generalmente exige el código JS explícito ahora se puede hacer declarativamente con los controles de hipermedia actualizados .
Aquí hay un ejemplo de este proyecto. Dos botones ( Cancelar y guardar ) que se pueden encontrar en casi todas las aplicaciones web suficientemente complejas.
< button hx-get =" /contacts "
hx-target =" #main "
hx-swap =" innerHTML " >
Cancel
</ button >
< button hx-post =" /contacts/{%contact.ID%}/edit "
hx-include =" input "
hx-target =" #main "
hx-swap =" innerHTML " >
Save
</ button >Lo creas o no, pero estos dos utilizan las siguientes funcionalidades:
<button> .Y no se necesitaba una sola línea de JavaScript para que funcione. Así de poderoso es realmente la arquitectura Hypermedia.
También usamos _hyperscript, una pequeña biblioteca para el manejo de eventos y la manipulación DOM. Con él, podemos escuchar y enviar eventos, manipular objetos DOM, todos sin dejar HTML.
Aquí hay un ejemplo de este proyecto:
< button id =" edit-c " class =" btn btn-primary "
hx-get =" /contacts/{%c.ID%}/edit "
hx-target =" #main "
hx-swap =" innerHTML " > Edit </ button >
< button class =" btn btn-danger "
hx-delete =" /contacts/{%c.ID%}/delete "
hx-confirm =" Are you sure you wish to delete this contact? "
hx-target =" this "
hx-swap =" none "
_ =" on click remove #edit-c
then remove me "
> Delete </ button >
< button class =" btn btn-info "
hx-get =" /contacts "
hx-target =" #main "
hx-swap =" innerHTML " > Back </ button > En el segundo control <button> tenemos algunos bits de _hyperscript que hace lo siguiente:
El resultado final es la eliminación de los botones Edit y Delete . Solo queda el botón Back .

En lugar de enviar Jsons de un lado a otro ( y cada vez que los analice de acuerdo con alguna lógica interna ), podemos usar HTML como diseñado originalmente: como un vehículo para aplicaciones de hipermedia significativas. El protocolo HTTP existe debido a HTML, pero en estos días transferimos principalmente JSON sobre él. En realidad, esto tiene poco sentido, porque JSON no puede transportar la semántica de aplicaciones, lo que efectivamente paraliza el significado original de la archiectura del cliente-servidor de la web. No es de extrañar que necesitemos marcos JS masivos en nuestros frontends, porque nuestros servidores son en su mayoría solo proveedores de datos con API JSON. Y las API JSON no son "relajantes".
El ejemplo de código fuente de backend del libro está escrito en Python y se puede usar en lugar de C ++. De hecho, he tratado de imitar las API originales de Python, para que no haya grandes brechas para comprenderlos a ambos. Estaba escribiendo el código C ++ mientras leía los capítulos respectivos.
Pero como htmx es un lenguaje agnóstico, no hay problema de usar ningún idioma, así que usé C ++. Esto también es bueno desde la perspectiva de aprendizaje, ya que me obliga a verificar todo.
Creo que deberíamos eliminar la hinchazón no solo de nuestros frontends [ poner cualquier marco JS masivo aquí ], sino también de nuestros backends [ poner cualquier marco de backend masivo aquí ]. El software masivo consume grandes cantidades de tiempo y energía. Tiempo y energía humana , así como ciclos de CPU y electricidad.
Se necesitan algunas bibliotecas de C ++ para que la compilación tenga éxito. Este proyecto usa VCPKG como su administrador de paquetes, pero puede elegir cualquier otro.
Para instalar un paquete, simplemente invoque vcpkg install PACKAGE_NAME .
Se necesitan los siguientes paquetes:
drogon
drogon[ctl]
fmt
argparse
brotli
zlib
openssl
sqlite3
soci[core]
soci[sqlite3]
La búsqueda de ellos es fácil: vcpkg search PACKAGE_NAME
sudo apt install uuid-dev libcriterion-dev
Los usuarios de Windows tendrán que configurar primero el entorno MSYS. Después de la instalación, seleccione la entrada MSYS2 MINGW64 en el menú de inicio de Windows. ¡No use el MSYS UCRT4 ni ninguna otra entrada!
En la ventana Bash recién abierta, ingrese este comando para instalar los paquetes requeridos:
pacman -S git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake make mingw-w64-x86_64-c-ares mingw-w64-x86_64-jsoncpp mingw-w64-x86_64-openssl
Compruebe si el compilador está disponible con which g++ . Deberías ver un mensaje como este:
$ which g++
/mingw64/bin/g++ También necesitará un editor para actualizar las rutas del entorno, así que instale su preferido, por ejemplo, pacman -Sy nano o pacman -Sy vim
Abra su .bash_profile con nano .$HOME/.bash_profile y agregue estas tres líneas al final del archivo:
PATH=/mingw64/bin: $PATH
export VCPKG_DEFAULT_TRIPLET=x64-mingw-static
export VCPKG_DEFAULT_HOST_TRIPLET=x64-mingw-static Guarde y cierre el archivo. Recargarlo con: source $HOME/.bash_profile o . ~/.bash_profile
Las dos entradas de triplete serán necesarias más adelante para instruir vcpkg que use MingW en lugar del compilador Visual C ++ Visual predeterminado. Y como también queremos compilar bibliotecas estáticas solo, lo anunciamos usando el sufijo static .
A diferencia de otros paquetes, Drogon no se instalará con vcpkg . El paquete VCPKG disponible actualmente THOWS Errores de compilación, que es la razón por la que tenemos que compilarlo manualmente.
Clonar las fuentes de Drogon y preparar el entorno de construcción. La ruta /c/bin/drogon del ejemplo a continuación debe adaptarse a su configuración local. La raíz de esta ruta ( /c/bin ) debe asignarse a una ruta ya existente en el sistema de Windows, por ejemplo, C:/bin o cualquier otra ruta de su elección.
git clone https://github.com/drogonframework/drogon --recursive
mkdir drogon/build
cd drogon/build
cmake .. -G " MSYS Makefiles " -DCMAKE_INSTALL_PREFIX:PATH=/c/bin/drogon Ahora compile Drogon con make -j y espere hasta que se complete.
Finalmente, instale Drogon con make install .
Ahora debería ver una lista de carpetas en C:/bin/drogon .

El segundo paso es la instalación de algunas bibliotecas que se vincularán estáticamente. Usaremos vcpkg para compilarlos a todos.
Desde la misma ventana Bash, emita los siguientes comandos para configurar vcpkg .
cd $HOME
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.batAviso:
If you pefer to install vcpkg files under different root path, change the first command "cd $HOME" from the script above.
For example: cd /c/Users/WINDOWS_USER_NAME
In MSYS Bash, the Windows file system is located under /c.
And your MSYS $HOME folder is located under "home" in your Windows MSYS root folder.
Desde la carpeta vcpkg , emita los siguientes comandos para instalar las bibliotecas requeridas:
./vcpkg.exe install argparse
./vcpkg.exe install fmt
./vcpkg.exe install brotli
./vcpkg.exe install zlib
./vcpkg.exe install openssl
./vcpkg.exe install sqlite3
./vcpkg.exe install soci
./vcpkg.exe install soci[sqlite3] Ahora puede compilar este proyecto a través de Poweshell con ./buildall.ps1 .
Pero no olvide cambiar vcpkg_root en meson.build primero. Esta ruta debe apuntar en el repositorio vcpkg clonado previamente.

Mi sistema de compilación de elección es Meson, porque Makefiles son difíciles de mantener y simplemente no quiero aprender a usar CMake . La vida es demasiado corta para el software de usuario-hostil.
Hay dos scripts, buildall.sh (macOS/Linux) y buildall.ps1 (Windows). Con estos dos se ejecutarán los siguientes pasos:
builddir ( solo en Windows, en MacOS/Linux, esto será hecho por Meson )drogon_ctl para convertir CSP en archivos de origen C ++ y colóquelos en src/viewssrcbuilddirSe necesita un compilador C ++ 20. Estoy usando GNU C ++ V12.1.0.
Antes de intentar construir el proyecto, por favor, adapte estas dos variables en el archivo meson.build :
El triplet lleva la información sobre la máquina host, por ejemplo, x64-osx .
El vcpkg_root es la carpeta raíz que contiene paquetes instalados por vcpkg .
drogon_ctl será utilizado por Meson para convertir las plantillas CSP en archivos C ++.

El frontend utiliza la biblioteca HTMX y algunos recursos Bootstrap para el estilo. No hay JavaScript escrito a mano en ejecución, ya que HTMX ya proporciona las cosas responsive que esperamos que ofrezca cualquier aplicación web modern .
El backend se basa en el marco web C ++ muy rápido llamado Drogon .
La base de datos en uso es SQLITE3 pero se puede reemplazar fácilmente con cualquier otra base de datos SQL. Simplemente ajuste la clase src/database/db_mgr.cpp . La biblioteca para acceder a SQLITE3 es SOCI y es compatible con muchos otros backends de bases de datos. La raíz de este proyecto contiene un archivo SQLITE3, demo.db , que la aplicación usa de forma predeterminada. También hay un archivo CSV disponible, contacts.csv , que contiene algunas entradas que se pueden usar para completar una nueva tabla.

controllers contienen clases que Drogon usa para mapear las llamadas del cliente a las funciones en el backend.database contiene una pequeña clase de envoltorio para acceder a la instancia SQLITE3.dtos contiene Data Transfer Objects que se utilizan para las tablas de datos entre Frontend y Backend.templates contienen CSP (páginas del servidor C ++), que son plantillas que drogon_ctl usa para generar fuentes de C ++. Estas fuentes se utilizarán para crear salidas HTML.views contienen clases C ++ generadas por Drogon. Estos archivos no deben editarse manualmente . Serán reemplazados en cada construcción. Para cambiar su comportamiento o contenido, use CSP de la carpeta de templates . Las pruebas se realizan con la biblioteca de criterios.
El criterio se puede instalar a través brew install criterion . De lo contrario, puede construirlo manualmente como se describe aquí.
Para construir criterio con Meson , clone su repositorio primero:
git clone --recursive https://github.com/Snaipe/Criterion.gitLuego emita los siguientes comandos:
cd Criterion
meson - Dprefix = c: / bin / criterion build
ninja - C build installSe puede cambiar el prefijo del directorio de instalación. Después de completar la instalación, configure la ruta al archivo DLL de Criterion. Esta DLL será utilizada por ejecutables de prueba que tienen criterio vinculado.

Las fuentes de prueba de este proyecto están ubicadas en test y están construidas automáticamente por Meson . Para ejecutar pruebas, puede usar estas dos opciones:
PS > meson test - C .builddir
ninja: no work to do .
ninja: Entering directory ` .builddir '
ninja: no work to do.
1/1 basic OK 0.09s
Ok: 1
Expected Fail: 0
Fail: 0
Unexpected Pass: 0
Skipped: 0
Timeout: 0
Full log written to .builddirmeson-logstestlog.txtO llamando directamente al ejecutable de prueba en sí:
PS > .builddir test_demo_web_server.exe
[ ==== ] Synthesis: Tested: 1 | Passing: 1 | Failing: 0 | Crashing: 0 La aplicación web comienza cargando el index.html que contiene una etiqueta div con id = "main" . A lo largo de la aplicación, esta etiqueta será utilizada por otros controles para reemplazar dinámicamente su contenido sin ninguna actualización de la página. Sin embargo, a diferencia de otras aplicaciones web modern típicas, no utilizamos marcos JS como React o Angular para que la aplicación responda. En cambio, solo usamos htmx como nuestra biblioteca de secuencias de comandos.
También hay tres recursos bootstrap involucrados, pero esto es solo hacer que la aplicación se vea mejor. Bootstrap no es un requisito y puede ser reemplazado por cualquier otra biblioteca o hojas de estilo propias. Lo mismo se aplica a jQuery que se incluye como dependencia de bootstrap. Cualquiera de esas bibliotecas se puede eliminar de manera segura ya que no afectan htmx o _hyperscript .
La aplicación web se comunica con el servidor de manera estándar de respuesta de solicitud. Pero a diferencia de muchas otras aplicaciones web, no se está utilizando JSON. En cambio, el servidor solo envía piezas de código HTML que el cliente usa para actualizar el estado actual de la aplicación.
El programa del servidor acepta dos parámetros para configurar la IP y el puerto.
Usage: demo_web_server [options]
Optional arguments:
-h --help shows help message and exits [default: false]
-v --version prints version information and exits [default: false]
-i --ip-address Server IP Address [default: " 127.0.0.1 " ]
-p --port Port [default: 3000]
También puede usar el Drogon's config.json incluido para controlar el comportamiento del servidor. Como Drogon ofrece muchas opciones, primero debe familiarizarse con él. El archivo de configuración en este proyecto contiene solo unas pocas configuraciones.
También existe un archivo de configuración basado en JSON separado, server_config.json , que será utilizado por el servidor web. Actualmente, solo define la ubicación del archivo SQLITE3, pero se ampliará en el futuro.
{
"database" : {
"type" : " sqlite3 " ,
"file" : " demo.db "
}
} Este archivo no debe confundirse con el propio JSON de Drogon, que se llama config.json .
MIT