This repo aims to provide an example of a complete setup for an HTMX app.
HTMX provides extensions for HTML, so that HTML content is really capable of fullfilling the Hypermedia As The Engine Of Application State paradigm that the web was designed for.
HTMX also features Hyperscript to create additional client-side interactions. In this repo, it's used in ./views/secret.pug and in ./views/app.pug.
We use Fastify as the Node backend (Fastify is "the new Express"), and Vite as the "bundler" for the frontend.
- Install Node
- Clone this repo
- Open a terminal and
cd
into the clone's root npm install
to install all dependencies and build the Vite projectnpm run dev
to start the Fastify server.
Browse to http://localhost:3000 and see that it worked.
If you're going to make changes to the JavaScript project in the vite
derictory, you can avoid having to rebuild it every time, by starting the Vite
development server:
- Open another terminal (keep Fastify running on port 3000 in the existing terminal)
cd
to thevite
foldernpm run dev
to start the Vite server on port 3001
Change the browser URL to http://localhost:3001. Now the browser will "hot reload" everything you change within the vite directory. Note that the Fastify server also restarts on every change of a file in the repo.
To demonstrate the setup, the app implements (not more than) a Register and Login sequence. Anyone can sign up by submitting their email address, which is stored in a database. Subsequently, an email is sent to that address, with a link to the password form. On submit, the token that was in the emailed link is verified, and the user record in the database is updated with a hash of the password. With the response, an encrypted cookie is set, which will authenticate the user on subsequent requests.
There's a live version running as an Azure App Service at https://fastify-htmxample.azurewebsites.net/. (It's hosted for free; it might take a minute to spin up for you)
To complete the intended functionality of the demo, you'd need the connection
details of an email box. Open app.js
and modify the configuration of the
fastify-mailer plugin. You can
enter a password in the code, or use an enivironment variable. For the
environment variable, stop the Fastify server (Ctrl-C
), then enter e.g.
export GMAIL_PASSWORD=xxxxxx
before you npm run dev
again.
Now, when you click the Register or New Password buttons in your browser, and submit an email addres, you should recieve an email with a link (containing an encrypted token) to the form where you can create your password to sign in.
Note that if you connect to a Gmail account, you probably need to set it to allow access from "less secure apps".
You'll notice that the URL in de browser changes on each action (e.g.
/users/session
), even when the HTML document isn't actually replaced, but only
updated with partial HTML content, that is requested through
Ajax.
Still, shoud you hit the browser's refresh button (or copy the URL and paste it in a new window), the complete HTML document is fetched, with the content matching the URL.
Should you navigate the site from a non-JavaScript environment, it would largely still work. Any machine that speaks HTTP can use it. In this sense, the site effectively behaves as a data API to the application's resources, using HTML as the data format. It's a self-describing format: it lists the data you've requested, along with links to any related resources, including all the parameters you can send on to those links, and a user interface to provision them. This is what's cool about hypermedia and REST.
Apart from HTMX, Hyperscript, Fastify and Vite, the main packages that make this setup work, are:
-
fastify-htmx, a Fastify plugin that arranges for:
- Serving the Vite build.
- Accepting Ajax requests (with cookies) from the Vite dev server.
- Serving the full document instead of the partial content when needed.
- HTMX utility functions as Fastify decorators.
-
dev-htmx, the frontend complement of fastify-htmx, to:
- Enable HTMX and Hyperscript.
- Direct Ajax requests to the backend server while the page is served by the frontend dev server.
- Fetch the inital app content from the backend, and insert it in the "empty" index.html from the frontend dev server.
Note that while we use Vite as the bundler in this repo, the dev-htmx package is not bound to it; you could replace Vite with any alternative that knows how to
import
things.
We use point-of-view to load the pug engine to dynamically render parametrised HTML. But again: you're free to make different choices.
From pug, we use fastify-mdc-pug to render Material Design Components. It's also imported client-side, to instantiate the JavaScript objects needed.
The .pug
files are in the views
directory. You'll notice the use of pug's
inheritance mechanism for
rendering either the partial content, requested by HTMX, or the full HTML,
including the surrounding app content.
To create a new project like this repo, take the following steps:
- Install fastify-cli:
npm install fastify-cli --global
fastify generate <yourapp>
cd <yourapp>
npm install
npm install fastify-htmx
- Edit
app.js
to register the plugin:fastify.register(require('fastify-htmx'))
- Optionally
npm install fastify-mdc-pug
andfastify.register(require('fastify-mdc-pug/plugin'))
npm init vite@latest vite
- choose vanilla or vanilla-ts (for TypeScript)cd vite
npm install
npm install dev-htmx
- Edit
main.js
:- Delete the lines setting
document.querySelector('#app').innerHTML
- Add the following:
import devHtmx from 'dev-htmx'
- Optionally
import 'fastify-mdc-pug'
devHtmx.init()
- Delete the lines setting
npm run build
cd ..
npm run dev
to start Fastify on port 3000- Browse to http://localhost:3000
- Optionally, in another terminal, in the vite directory:
npm run dev
to start the Vite server on port 3001, and change the browser's address to http://localhost:3001
- Add tests and remove
--no-check-coverage
from package.json. - Have the GUI handle HTTP error codes 4xx/5xx.
- Please file a GitHub issue should you have comments, find bugs, or request new features.
Kudos to the fine people on HTMX's Discord.
Getting Started with Fastify-CLI Fastify-CLI
This project was bootstrapped with Fastify-CLI.
In the project directory, you can run:
To start the app in dev mode.
Open http://localhost:3000 to view it in the browser.
For production mode
Run the test cases.
To learn Fastify, check out the Fastify documentation.