|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Reactive HTML Without JavaScript Frameworks" |
| 4 | +date: 2025-07-07 2:10 PM |
| 5 | +categories: blog |
| 6 | +--- |
| 7 | + |
| 8 | +Hello everyone! In this article, I'll show you how to create reactive HTML interfaces without relying on heavy JavaScript frameworks like Vue or Angular. We'll explore how HMPL.js provides a lightweight alternative that achieves reactivity through server-side rendering while keeping your client-side code minimal. |
| 9 | + |
| 10 | +## The Problem with JavaScript Frameworks |
| 11 | + |
| 12 | +In the modern web development landscape, JavaScript frameworks like Vue and Angular dominate discussions about reactive interfaces. However, they come with significant drawbacks that can impact your project: |
| 13 | + |
| 14 | +### Common Framework Issues |
| 15 | + |
| 16 | +- **Boilerplate Code**: Developers often write repetitive setup code before implementing actual features |
| 17 | +- **Overly Complex Architecture**: Frameworks impose their own architecture that can be too complex for simple projects |
| 18 | +- **Performance Overhead**: Large runtime libraries bundle unnecessary code |
| 19 | +- **Vendor Lock-in**: Makes it harder to switch technologies later |
| 20 | +- **Bundle Size**: Many projects use only a fraction of a framework's features yet pay the full cost |
| 21 | + |
| 22 | +For smaller applications, a lightweight alternative like HMPL.js can often achieve reactivity **without unnecessary bloat**. |
| 23 | + |
| 24 | +## The HMPL.js Solution |
| 25 | + |
| 26 | +HMPL.js takes a different approach by leveraging server-side rendering while maintaining reactivity on the client. Instead of loading heavy frameworks, you can create reactive interfaces with just a few script tags. |
| 27 | + |
| 28 | +### Key Benefits |
| 29 | + |
| 30 | +1. **Minimal Client Code**: Only a few kilobytes of JavaScript |
| 31 | +2. **Server-Oriented**: Components are rendered on the server and loaded dynamically |
| 32 | +3. **No Framework Dependencies**: Pure HTML with lightweight HMPL.js |
| 33 | +4. **Reusable Components**: Components can be shared across different web applications |
| 34 | + |
| 35 | +## Getting Started with HMPL.js |
| 36 | + |
| 37 | +Let's look at a simple example that demonstrates how to create reactive HTML without heavy frameworks: |
| 38 | + |
| 39 | +```html |
| 40 | +<!DOCTYPE html> |
| 41 | +<html lang="en"> |
| 42 | + <head> |
| 43 | + <meta charset="UTF-8" /> |
| 44 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 45 | + <title>Reactive HTML Example</title> |
| 46 | + </head> |
| 47 | + <body> |
| 48 | + <main> |
| 49 | + <template hmpl> |
| 50 | + <div> |
| 51 | + {{#request src="/api/header.html"}} |
| 52 | + {{#indicator trigger="error"}} |
| 53 | + <p class="indicator">Header loading error</p> |
| 54 | + {{/indicator}} |
| 55 | + {{/request}} |
| 56 | + </div> |
| 57 | + </template> |
| 58 | + |
| 59 | + <div class="content"></div> |
| 60 | + |
| 61 | + <template hmpl> |
| 62 | + <div> |
| 63 | + {{#request src="/api/footer.html"}} |
| 64 | + {{#indicator trigger="error"}} |
| 65 | + <p class="indicator">Footer loading error</p> |
| 66 | + {{/indicator}} |
| 67 | + {{/request}} |
| 68 | + </div> |
| 69 | + </template> |
| 70 | + </main> |
| 71 | + |
| 72 | + <script src="https://unpkg.com/json5/dist/index.min.js"></script> |
| 73 | + <script src="https://unpkg.com/dompurify/dist/purify.min.js"></script> |
| 74 | + <script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script> |
| 75 | + <script src="https://unpkg.com/hmpl-dom/dist/hmpl-dom.min.js"></script> |
| 76 | + </body> |
| 77 | +</html> |
| 78 | +``` |
| 79 | + |
| 80 | +### How It Works |
| 81 | + |
| 82 | +1. **Server-Side Components**: Your components are stored as HTML files on the server |
| 83 | +2. **Dynamic Loading**: HMPL.js fetches components from the server when needed |
| 84 | +3. **Error Handling**: Built-in error indicators for failed requests |
| 85 | +4. **Minimal Dependencies**: Only requires a few lightweight libraries |
| 86 | + |
| 87 | +## Server-Side Implementation |
| 88 | + |
| 89 | +On your server, you can serve components as simple HTML files: |
| 90 | + |
| 91 | +**/api/header.html** |
| 92 | +```html |
| 93 | +<header class="site-header"> |
| 94 | + <nav> |
| 95 | + <a href="/">Home</a> |
| 96 | + <a href="/about">About</a> |
| 97 | + <a href="/contact">Contact</a> |
| 98 | + </nav> |
| 99 | +</header> |
| 100 | +``` |
| 101 | + |
| 102 | +**/api/footer.html** |
| 103 | +```html |
| 104 | +<footer class="site-footer"> |
| 105 | + <p>© 2025 Your Website. All rights reserved.</p> |
| 106 | +</footer> |
| 107 | +``` |
| 108 | + |
| 109 | +## Advanced Features |
| 110 | + |
| 111 | +### Reactive Data Binding |
| 112 | + |
| 113 | +HMPL.js supports reactive data binding without the complexity of full frameworks: |
| 114 | + |
| 115 | +```html |
| 116 | +<template hmpl> |
| 117 | + <div> |
| 118 | + {{#request src="/api/user-profile.html" data="userData"}} |
| 119 | + <div class="user-profile"> |
| 120 | + <h2>{{userData.name}}</h2> |
| 121 | + <p>{{userData.email}}</p> |
| 122 | + </div> |
| 123 | + {{/request}} |
| 124 | + </div> |
| 125 | +</template> |
| 126 | +``` |
| 127 | + |
| 128 | +### Event Handling |
| 129 | + |
| 130 | +You can handle user interactions with simple event listeners: |
| 131 | + |
| 132 | +```html |
| 133 | +<button onclick="updateProfile()">Update Profile</button> |
| 134 | + |
| 135 | +<script> |
| 136 | +function updateProfile() { |
| 137 | + // HMPL.js will automatically re-render the component |
| 138 | + hmpl.request('/api/user-profile.html', { userId: 123 }); |
| 139 | +} |
| 140 | +</script> |
| 141 | +``` |
| 142 | + |
| 143 | +## Performance Benefits |
| 144 | + |
| 145 | +### Bundle Size Comparison |
| 146 | + |
| 147 | +| Framework | Bundle Size | HMPL.js | |
| 148 | +|-----------|-------------|---------| |
| 149 | +| Vue.js | ~33KB | ~5KB | |
| 150 | +| Angular | ~135KB | ~5KB | |
| 151 | + |
| 152 | +### Loading Performance |
| 153 | + |
| 154 | +- **Initial Load**: Only loads essential HMPL.js libraries |
| 155 | +- **Component Loading**: Components are loaded on-demand |
| 156 | +- **Caching**: Server-side components can be cached effectively |
| 157 | +- **SEO Friendly**: Content is available to search engines |
| 158 | + |
| 159 | +## When to Use HMPL.js |
| 160 | + |
| 161 | +### Perfect For: |
| 162 | +- **Simple to Medium Applications**: Where full frameworks are overkill |
| 163 | +- **Content-Heavy Sites**: Blogs, documentation, marketing sites |
| 164 | +- **Prototypes**: Quick development without framework setup |
| 165 | +- **Legacy Integration**: Adding reactivity to existing HTML sites |
| 166 | + |
| 167 | +### Consider Alternatives When: |
| 168 | +- **Complex State Management**: Applications with complex state requirements |
| 169 | +- **Real-time Features**: Applications requiring WebSocket connections |
| 170 | +- **Large Teams**: Teams already invested in specific frameworks |
| 171 | + |
| 172 | +## Comparison with Other Solutions |
| 173 | + |
| 174 | +### vs. HTMX |
| 175 | +- **HMPL.js**: More focused on component-based architecture |
| 176 | +- **HTMX**: Better for full-page updates and form handling |
| 177 | + |
| 178 | +### vs. Alpine.js |
| 179 | +- **HMPL.js**: Server-oriented with minimal client code |
| 180 | +- **Alpine.js**: Client-side reactivity with more JavaScript |
| 181 | + |
| 182 | +### vs. Vanilla JavaScript |
| 183 | +- **HMPL.js**: Provides structure and conventions |
| 184 | +- **Vanilla JS**: Complete freedom but requires more boilerplate |
| 185 | + |
| 186 | +## Best Practices |
| 187 | + |
| 188 | +### 1. Component Organization |
| 189 | +``` |
| 190 | +/api/ |
| 191 | + ├── header.html |
| 192 | + ├── footer.html |
| 193 | + ├── sidebar.html |
| 194 | + └── components/ |
| 195 | + ├── user-card.html |
| 196 | + └── product-list.html |
| 197 | +``` |
| 198 | + |
| 199 | +### 2. Error Handling |
| 200 | +Always include error indicators in your templates: |
| 201 | + |
| 202 | +```html |
| 203 | +{{#request src="/api/component.html"}} |
| 204 | + {{#indicator trigger="error"}} |
| 205 | + <p class="error">Failed to load component</p> |
| 206 | + {{/indicator}} |
| 207 | + {{#indicator trigger="loading"}} |
| 208 | + <p class="loading">Loading...</p> |
| 209 | + {{/indicator}} |
| 210 | +{{/request}} |
| 211 | +``` |
| 212 | + |
| 213 | +### 3. Performance Optimization |
| 214 | +- **Cache Components**: Use server-side caching for frequently accessed components |
| 215 | +- **Minimize Requests**: Group related components when possible |
| 216 | +- **Lazy Loading**: Load components only when needed |
| 217 | + |
| 218 | +## Conclusion |
| 219 | + |
| 220 | +JavaScript frameworks provide powerful solutions but often introduce unnecessary complexity, boilerplate code, and performance overhead for simpler applications. Lightweight alternatives like HMPL.js demonstrate that reactivity can be achieved without heavy dependencies, offering a more efficient approach for many use cases. |
| 221 | + |
| 222 | +By carefully evaluating project needs, developers can choose the right balance between functionality and simplicity, avoiding over-engineering while still delivering dynamic user experiences. |
| 223 | + |
| 224 | +### Key Takeaways |
| 225 | + |
| 226 | +1. **Server-Oriented Approach**: Components are rendered on the server and loaded dynamically |
| 227 | +2. **Minimal Client Code**: Only a few kilobytes of JavaScript required |
| 228 | +3. **No Framework Lock-in**: Pure HTML with lightweight HMPL.js |
| 229 | +4. **Better Performance**: Smaller bundle sizes and faster loading |
| 230 | +5. **SEO Friendly**: Content is available to search engines |
| 231 | + |
| 232 | +HMPL.js represents a practical middle ground between full frameworks and vanilla JavaScript, providing the reactivity you need without the complexity you don't. |
| 233 | + |
| 234 | +--- |
| 235 | + |
| 236 | +*This article is based on the original tutorial by Anthony Max, available on [Dev.to](https://dev.to/anthonymax/reactive-html-without-javascript-frameworks-1anh).* |
0 commit comments