Skip to content

Commit 07e2ea3

Browse files
committed
Add HTMX integration example and documentation (draft)
- Created website/examples/htmx-integration.html with interactive demo - Demonstrates cleanup patterns for DOM swapping - Simulates HTMX behavior with client-side JavaScript - Uses cyberpunk/terminal aesthetic per DESIGN-SYSTEM.md - Includes ServerUptime components with setInterval timers - Created website/examples/htmx-integration.js - ServerUptime component with proper cleanup in run() - Global htmx:beforeCleanup event listener - Console logging for debugging/demonstration - Created wiki/INTEGRATIONS.md - Comprehensive guide for HTMX, Turbo, Alpine.js integration - Explains Macro vs Micro architecture philosophy - Documents cleanup patterns and best practices - Includes testing patterns and common pitfalls - Updated website/examples/examples.json - Added 'status' field to all examples - All existing examples marked as 'published' - HTMX integration marked as 'draft' (not shown in index yet) - Added HTMX integration metadata - Updated website/examples/index.html - HTMX integration card commented out (draft status) - Ready to uncomment when example is production-ready This implements the 'Missing Link' in front.js documentation, proving the framework handles DOM thrashing gracefully without memory leaks when integrated with macro frameworks like HTMX.
1 parent f9942bd commit 07e2ea3

File tree

5 files changed

+777
-0
lines changed

5 files changed

+777
-0
lines changed

website/examples/examples.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"description": "Derived state and complex event handling",
99
"htmlFile": "calculator.html",
1010
"jsFile": "calculator.js",
11+
"status": "published",
1112
"runtime": {
1213
"browser": true,
1314
"node": false,
@@ -29,6 +30,7 @@
2930
"description": "Simple CRUD with input handling and list rendering",
3031
"htmlFile": "todo.html",
3132
"jsFile": "todo-app.js",
33+
"status": "published",
3234
"runtime": {
3335
"browser": true,
3436
"node": false,
@@ -50,6 +52,7 @@
5052
"description": "Async data fetching with the \"Active Flag\" pattern to prevent race conditions",
5153
"htmlFile": "github-user.html",
5254
"jsFile": "github-user.js",
55+
"status": "published",
5356
"runtime": {
5457
"browser": true,
5558
"node": false,
@@ -74,6 +77,7 @@
7477
"description": "Lifecycle management (cleanup), audio feedback, and timers",
7578
"htmlFile": "walking-timer.html",
7679
"jsFile": "walking-timer.js",
80+
"status": "published",
7781
"runtime": {
7882
"browser": true,
7983
"node": false,
@@ -100,6 +104,7 @@
100104
"description": "Shared state, multi-island communication, and canvas rendering",
101105
"htmlFile": "pixel-art.html",
102106
"jsFile": "pixel-art.js",
107+
"status": "published",
103108
"runtime": {
104109
"browser": true,
105110
"node": false,
@@ -125,6 +130,7 @@
125130
"description": "Forms, auth flow simulation, and nested state",
126131
"htmlFile": "gm-board.html",
127132
"jsFile": "gm-board.js",
133+
"status": "published",
128134
"runtime": {
129135
"browser": true,
130136
"node": false,
@@ -151,6 +157,7 @@
151157
"description": "Responsive navigation bar with mobile toggle",
152158
"htmlFile": "navbar.html",
153159
"jsFile": "../components/NavBar.js",
160+
"status": "published",
154161
"runtime": {
155162
"browser": true,
156163
"node": false,
@@ -164,6 +171,24 @@
164171
"browserAPIs": [],
165172
"tested": true,
166173
"notes": "Responsive component with mobile menu toggle. Used throughout the website."
174+
},
175+
{
176+
"id": "htmx-integration",
177+
"title": "HTMX Integration",
178+
"description": "Macro meets Micro: DOM swapping with proper cleanup patterns to prevent memory leaks",
179+
"htmlFile": "htmx-integration.html",
180+
"jsFile": "htmx-integration.js",
181+
"status": "draft",
182+
"runtime": {
183+
"browser": true,
184+
"node": false,
185+
"deno": false,
186+
"bun": false
187+
},
188+
"features": ["val", "run", "html"],
189+
"browserAPIs": ["setInterval", "CustomEvent"],
190+
"tested": false,
191+
"notes": "Demonstrates cleanup patterns for HTMX integration. Shows how to prevent memory leaks when DOM nodes are swapped. Includes global HTMX event listener setup."
167192
}
168193
]
169194
}
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta name="description" content="Demonstrates front.js + HTMX integration with proper cleanup patterns for memory leak prevention." />
7+
<title>front.js + HTMX Integration</title>
8+
9+
<!-- Canonical URL -->
10+
<link rel="canonical" href="https://frontjs.dev/examples/htmx-integration.html" />
11+
12+
<!-- Favicon -->
13+
<link rel="icon" href="../favicon.svg" type="image/svg+xml" />
14+
<link rel="alternate icon" href="../favicon.ico" />
15+
16+
<!-- Preconnect to CDNs -->
17+
<link rel="preconnect" href="https://esm.sh" crossorigin />
18+
<link rel="preconnect" href="https://unpkg.com" crossorigin />
19+
<link rel="dns-prefetch" href="https://esm.sh" />
20+
<link rel="dns-prefetch" href="https://unpkg.com" />
21+
22+
<link rel="stylesheet" href="../styles.css" />
23+
24+
<style>
25+
.demo-section {
26+
background: var(--color-bg-light);
27+
border: 1px solid var(--color-border);
28+
border-radius: var(--border-radius);
29+
padding: 2rem;
30+
margin-bottom: 2rem;
31+
}
32+
33+
.server-list {
34+
display: grid;
35+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
36+
gap: 1rem;
37+
margin-top: 1rem;
38+
}
39+
40+
.server-card {
41+
background: var(--color-code-bg);
42+
border: 1px solid var(--color-border);
43+
border-radius: 4px;
44+
padding: 1rem;
45+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
46+
}
47+
48+
.server-name {
49+
color: var(--color-primary);
50+
font-weight: bold;
51+
margin-bottom: 0.5rem;
52+
}
53+
54+
.server-uptime {
55+
color: var(--color-text-light);
56+
font-size: 0.9rem;
57+
}
58+
59+
.status-indicator {
60+
display: inline-block;
61+
width: 8px;
62+
height: 8px;
63+
border-radius: 50%;
64+
background: var(--color-primary);
65+
margin-right: 0.5rem;
66+
animation: pulse 2s ease-in-out infinite;
67+
}
68+
69+
@keyframes pulse {
70+
0%, 100% { opacity: 1; }
71+
50% { opacity: 0.5; }
72+
}
73+
74+
.htmx-indicator {
75+
color: var(--color-primary);
76+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
77+
}
78+
79+
.refresh-button {
80+
background: var(--color-primary);
81+
color: var(--color-bg);
82+
border: none;
83+
padding: 0.75rem 1.5rem;
84+
border-radius: 4px;
85+
font-weight: bold;
86+
text-transform: uppercase;
87+
cursor: pointer;
88+
font-size: 0.9rem;
89+
letter-spacing: 0.05em;
90+
transition: all 0.2s ease;
91+
}
92+
93+
.refresh-button:hover {
94+
background: var(--color-primary-dark);
95+
transform: translateY(-2px);
96+
}
97+
98+
.refresh-button:active {
99+
transform: translateY(0);
100+
}
101+
102+
.console-hint {
103+
background: var(--color-code-bg);
104+
border-left: 3px solid var(--color-primary);
105+
padding: 1rem;
106+
margin-top: 1rem;
107+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
108+
font-size: 0.9rem;
109+
}
110+
111+
.console-hint code {
112+
color: var(--color-primary);
113+
}
114+
</style>
115+
</head>
116+
117+
<body>
118+
<div
119+
data-island
120+
data-component="NavBar"
121+
data-props='{
122+
"links": [
123+
{"label": "Home", "url": "../"},
124+
{"label": "Examples", "url": "./"},
125+
{"label": "Docs", "url": "../KB/"},
126+
{"label": "GitHub", "url": "https://github.com/watthem/front-js"}
127+
]
128+
}'
129+
></div>
130+
131+
<div class="container" style="padding-top: 60px">
132+
<header class="hero">
133+
<h1>HTMX Integration</h1>
134+
<p class="tagline">Macro meets Micro: DOM Swapping with Cleanup</p>
135+
<p class="description">
136+
This example demonstrates how front.js components handle <strong>DOM thrashing</strong>
137+
from macro-frameworks like HTMX without memory leaks.
138+
</p>
139+
</header>
140+
141+
<section class="demo-section">
142+
<h2>Server Status Dashboard</h2>
143+
<p>
144+
Click "Refresh Server List" to simulate an HTMX swap.
145+
Watch the console to see cleanup functions being called.
146+
</p>
147+
148+
<button
149+
class="refresh-button"
150+
onclick="simulateHTMXSwap()"
151+
>
152+
🔄 Refresh Server List
153+
</button>
154+
<span class="htmx-indicator" id="swap-indicator"></span>
155+
156+
<div class="console-hint">
157+
💡 <strong>Tip:</strong> Open DevTools Console (<code>F12</code>) to see cleanup logs
158+
</div>
159+
160+
<div id="server-container" class="server-list">
161+
<!-- Islands will be hydrated here -->
162+
<div
163+
data-island
164+
data-component="ServerUptime"
165+
data-props='{"name": "web-prod-01", "region": "us-east-1"}'
166+
></div>
167+
168+
<div
169+
data-island
170+
data-component="ServerUptime"
171+
data-props='{"name": "web-prod-02", "region": "us-west-2"}'
172+
></div>
173+
174+
<div
175+
data-island
176+
data-component="ServerUptime"
177+
data-props='{"name": "api-prod-01", "region": "eu-central-1"}'
178+
></div>
179+
</div>
180+
</section>
181+
182+
<section class="demo-section">
183+
<h2>How It Works</h2>
184+
<p>
185+
<strong>The Problem:</strong> When HTMX (or similar libraries) swap DOM content,
186+
components with timers, event listeners, or other side effects can leak memory if not cleaned up.
187+
</p>
188+
<p>
189+
<strong>The Solution:</strong> front.js attaches a <code>_front_dispose</code> function
190+
to each island container. Before HTMX swaps content, we call this function to cleanup all
191+
reactive runs and their side effects.
192+
</p>
193+
<pre style="background: var(--color-code-bg); padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>// Global HTMX cleanup handler
194+
document.body.addEventListener('htmx:beforeCleanup', (event) => {
195+
if (event.target._front_dispose) {
196+
event.target._front_dispose();
197+
}
198+
});</code></pre>
199+
</section>
200+
201+
<footer class="footer">
202+
<p>
203+
<a href="./">Back to Examples</a> |
204+
<a href="../KB/">Documentation</a> |
205+
<a href="https://github.com/watthem/front-js">GitHub</a>
206+
</p>
207+
<p class="license">ISC License</p>
208+
</footer>
209+
</div>
210+
211+
<!-- HTMX from CDN -->
212+
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
213+
214+
<!-- Load uhtml from CDN -->
215+
<script type="importmap">
216+
{
217+
"imports": {
218+
"uhtml": "https://esm.sh/uhtml@4.5.11"
219+
}
220+
}
221+
</script>
222+
223+
<!-- Simulation script (since we can't hit a real backend) -->
224+
<script>
225+
function simulateHTMXSwap() {
226+
const container = document.getElementById('server-container');
227+
const indicator = document.getElementById('swap-indicator');
228+
229+
indicator.textContent = '⚡ Swapping...';
230+
231+
// Fire beforeCleanup event (simulating HTMX behavior)
232+
const beforeEvent = new CustomEvent('htmx:beforeCleanup', {
233+
detail: { target: container },
234+
bubbles: true
235+
});
236+
beforeEvent.target = container;
237+
document.body.dispatchEvent(beforeEvent);
238+
239+
// Simulate swap delay
240+
setTimeout(() => {
241+
// Clear and rebuild islands with new data
242+
container.innerHTML = `
243+
<div
244+
data-island
245+
data-component="ServerUptime"
246+
data-props='{"name": "web-prod-03", "region": "ap-southeast-1"}'
247+
></div>
248+
249+
<div
250+
data-island
251+
data-component="ServerUptime"
252+
data-props='{"name": "db-prod-01", "region": "us-east-1"}'
253+
></div>
254+
255+
<div
256+
data-island
257+
data-component="ServerUptime"
258+
data-props='{"name": "cache-prod-01", "region": "eu-west-1"}'
259+
></div>
260+
`;
261+
262+
// Re-hydrate new islands
263+
if (window.front && window.front.hydrate) {
264+
window.front.hydrate();
265+
}
266+
267+
indicator.textContent = '✅ Swapped!';
268+
setTimeout(() => { indicator.textContent = ''; }, 2000);
269+
}, 500);
270+
}
271+
</script>
272+
273+
<!-- Load front.js and components -->
274+
<script type="module">
275+
import { register, hydrate } from '../front.esm.js';
276+
import { NavBar } from '../components/NavBar.js';
277+
278+
// Register NavBar component
279+
register('NavBar', NavBar);
280+
281+
// Import HTMX integration component
282+
const module = await import('./htmx-integration.js');
283+
register('ServerUptime', module.ServerUptime);
284+
285+
// Expose for simulation script
286+
window.front = { hydrate };
287+
288+
// Hydrate initial islands
289+
hydrate();
290+
</script>
291+
</body>
292+
</html>

0 commit comments

Comments
 (0)