Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add HTMX to the examples #2265

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/htmx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
4 changes: 4 additions & 0 deletions examples/htmx/.jshintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/

public/js/htmx.min.js
public/todomvc-common/base.js
20 changes: 20 additions & 0 deletions examples/htmx/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"node": true,
"browser": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 4,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"white": true,
"esversion": 8
}
1 change: 1 addition & 0 deletions examples/htmx/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.0.0
14 changes: 14 additions & 0 deletions examples/htmx/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"plugins": ["prettier-plugin-ejs"],
"singleQuote": true,
"trailingComma": "es5",
"useTabs": true,
"overrides": [
{
"files": "*.ejs",
"options": {
"parser": "html"
}
}
]
}
78 changes: 78 additions & 0 deletions examples/htmx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# HTMX TodoMVC

**A simple, feature-complete To-Do application using HTMX**

This project provides a fully functional To-Do list app that leverages [HTMX](https://htmx.org/) to handle front-end interactivity without traditional JavaScript frameworks, instead relying on built-in web standards for optimal performance. This app demonstrates how HTMX can efficiently manage dynamic content with minimal JavaScript.

## Prerequisites
* **NodeJS v20.0.0** (or higher)
* **NPM v9.6.4** (or higher)

If you're using `nvm`, you can run `nvm use` from the HTMX example directory, and `nvm` will manage the Node version for you.

## Getting Started
1. Navigate to the project's directory:
```bash
cd examples/htmx
```
2. Install NPM dependencies by running:
```bash
npm install
```
3. Start the web server:
```bash
npm run start
```

That's it!
Open your browser and navigate to http://localhost:3000/ to start using the app. Enjoy!


## Architecture

### Tech Stack
* **Server** - [Fastify](https://fastify.dev/)
* **Templating engine** - [EJS](https://ejs.co/)
* **Client** - [HTMX](https://htmx.org/), Plain JavaScript
* **Styling** - Plain CSS

### Web App Container
The server handles most of the application’s "heavy lifting" and consists of 4 main components:
| Component | Description |
| --------------- | --------------------------------------------------------------------------- |
| **TodosRouter** | Defines the routes the client uses to interact with the app |
| **TodosAPI** | The "Model" - Holds and manipulates the todos data, handling all CRUD ops |
| **Templating engine** | The "View" - Renders HTML from the data |
| **TodosController** | The "Controller" - Handles requests, using TodosAPI to compose HTML |

Below is a diagram showing the relationship between these components:

![HTMX TodoMVC web app container diagram](images/web-app-container-diagram.png)

### Client-Server Communication
All client-server communication uses HTTP requests, following REST principles where possible (e.g., `POST` for creating new todos, `DELETE` for deleting them, `PATCH` for updating them, etc.).

### Application State and Routes
State is managed on the server, so refreshing the page preserves the current application state without relying on local or session storage, making it closer to real-world applications.
Filtering is achieved through application routing. For instance, if you land on a page with a filter applied, such as `http://localhost:3000/?filter=completed`, the page displays the filtered todo list along with the appropriate footer.

### Swapping Markup
Navigating to `http://localhost:3000` initially fetches the entire application markup. However, after that, any interaction only updates a portion of the page, reducing page refresh flicker.
The entire application uses [hx-boost](https://htmx.org/attributes/hx-boost/), so even when filtering todos, which navigates to a new `href`, only the relevant markup is fetched, avoiding a full page reload.
To further optimize performance, [eTag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) is implemented for Fastify, enabling caching for improved speed.

### Oh, and BTW...
No Webpack, no Babel – none of the usual build tools – just the capabilities provided by modern web standards.

## Developer
In case you would like to tweak this application you will find it convenient to launch the application with [nodemon](https://nodemon.io/). You can do it by running the following command:
```bash
npm run start:dev
```

## Credits

Created by **Matti Bar-Zeev**
[![Twitter](https://img.shields.io/badge/X-Profile-blue?logo=twitter&logoColor=white&style=flat-square)](https://x.com/mattibarzeev)
[![Dev.to](https://img.shields.io/badge/Dev.to-Profile-black?logo=dev.to&logoColor=white&style=flat-square)](https://dev.to/mbarzeev)
[![LinkedIn](https://img.shields.io/badge/LinkedIn-Profile-blue?logo=linkedin&logoColor=white&style=flat-square)](https://www.linkedin.com/in/matti-bar-zeev/)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions examples/htmx/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

import fastifyFactoryFunc from 'fastify';
import fastifyStatic from '@fastify/static';
import path from 'path';
import TodoRouter from './todos/todos-router.js';
import formBody from '@fastify/formbody';
import Etag from '@fastify/etag';

const fastify = fastifyFactoryFunc({
logger: {
transport: {
target: 'pino-pretty',
options: {
colorize: true,
},
},
},
});

fastify.register(Etag, { algorithm: 'fnv1a' });

fastify.register(fastifyStatic, {
root: path.resolve('public'),
prefix: '/',
});

fastify.register(formBody);

// Routers
const todoRouter = new TodoRouter();
todoRouter.initRoutes(fastify);

fastify.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err);
process.exit(1);
}
});
Loading