<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en_US"><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://blog.hmpl-lang.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.hmpl-lang.dev/" rel="alternate" type="text/html" hreflang="en_US" /><updated>2025-11-27T21:54:50+00:00</updated><id>https://blog.hmpl-lang.dev/feed.xml</id><title type="html">HMPL Blog</title><subtitle>HMPL Blog - HMPL.js is a lightweight server-oriented template language for JavaScript. 
     Fetch HTML, render it safely, and keep apps dynamic, modern, and small.
</subtitle><author><name>HMPL Team</name><email>contact@hmpl-lang.dev</email></author><entry><title type="html">What Is HATEOAS? A Complete Guide + Build Your Own App Using Hypermedia</title><link href="https://blog.hmpl-lang.dev/2025/11/27/what-is-hateoas/" rel="alternate" type="text/html" title="What Is HATEOAS? A Complete Guide + Build Your Own App Using Hypermedia" /><published>2025-11-27T20:00:00+00:00</published><updated>2025-11-27T20:00:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/11/27/what-is-hateoas</id><author><name>HMPL Team</name></author><category term="blog" /><category term="webdev" /><category term="html" /><summary type="html"><![CDATA[Surely most people have encountered the concept of HATEOAS at least once, but what exactly is it? In fact, this is a rather old, but very interesting topic even today, which has not lost its relevance in development. In this article, we will cover the basics and create our first simple application that will reflect this topic. Ready? Then let’s get to the topic! 🔎 What is this? Many would start with a definition, but without some understanding, we’ll naturally leave it at that for now. Let’s first look at how our app works. Let’s say we have a typical SPA application built on some popular framework. Let’s review how we retrieve data from it. We retrieve data from API routes defined in advance on the client, but what if the route changes? What if we work in a large company with several thousand employees and never know which backend is currently up-to-date? Perhaps now we come to the definition of what HATEOAS is. HATEOAS - Hypermedia As The Engine Of Application State. This means that we will take one specific existing route, and we will describe the actions for it based on the response object. 📦 Architectural structure of the application Now, let’s look at some specific examples of what this concept offers for our SPA app. Let’s take a simple online clothes store. We know that product reviews come from our API via the specified reviews/{id} route, but one day, they simply delete it and integrate it with a review platform. As a result, when users go to buy jacket, for example, they open the reviews section, but an error occurs on the page, and the app stops working. For these kinds of cases, we can create a different application. We won’t discuss the BFF layer here; let’s focus on our topic. What if we simply create an products/{id} route and retrieve the data we need from there? Let’s see how this would look in a diagram: We see that we have a list of links we can work with. Now, we can simply create a button with a link from the response, and when clicked, we’ll get the route we need. This way, we can literally build the entire application with just a couple of routes for each page. 🔧 Creating an application Now, let’s create a small app for our clothing store. The functionality will be simple: we’ll tap on an item and get information about it. For work we will use hmpl-js via the hmpl-dom extension for working through one html. &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="utf-8" /&gt; &lt;meta name="viewport" content="width=device-width,initial-scale=1" /&gt; &lt;title&gt;Mini HATEOAS Shop&lt;/title&gt; &lt;style&gt; body { padding: 20px; } .item { padding: 8px; border: 1px solid #ddd; margin: 6px 0; cursor: pointer; border-radius: 6px; } .back { color: blue; cursor: pointer; margin-top: 10px; display: inline-block; } pre { background: #f6f6f6; padding: 8px; border-radius: 6px; } &lt;/style&gt; &lt;script&gt; (function () { const products = [ { id: 1, name: "T-Shirt", price: 15 }, { id: 2, name: "Hoodie", price: 40 }, { id: 3, name: "Jeans", price: 55 } ]; const real = fetch.bind(window); window.fetch = async (input, init) =&gt; { const url = typeof input === "string" ? input : input?.url || ""; await new Promise((r) =&gt; setTimeout(r, 80)); if (url.endsWith("/api/products")) { return new Response( products .map( (p) =&gt; ` &lt;div class="item" data-id="${p.id}"&gt; &lt;strong&gt;${p.name}&lt;/strong&gt; — $${p.price} &lt;/div&gt;` ) .join(""), { status: 200, headers: { "Content-Type": "text/html" } } ); } if (/\/api\/product\/\d+$/.test(url)) { const id = +url.split("/").pop(); const p = products.find((x) =&gt; x.id === id); return new Response( ` &lt;h2&gt;${p.name}&lt;/h2&gt; &lt;p&gt;Price: $${p.price}&lt;/p&gt; &lt;div class="back" data-back="/api/products"&gt;← Back&lt;/div&gt; &lt;pre data-hateoas&gt;${JSON.stringify( { self: `/api/product/${p.id}`, add_to_cart: `/api/cart/add/${p.id}` }, null, 2 )}&lt;/pre&gt; `, { status: 200, headers: { "Content-Type": "text/html" } } ); } return real(input, init); }; })(); &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;template data-hmpl&gt; &lt;div&gt; &lt;h1&gt;Clothing Shop — HATEOAS&lt;/h1&gt; &lt;div id="list"&gt; Loading… &lt;/div&gt; &lt;div id="detail"&gt;&lt;/div&gt; &lt;h3&gt;Info:&lt;/h3&gt; &lt;pre id="info"&gt;none&lt;/pre&gt; &lt;/div&gt; &lt;/template&gt; &lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/dompurify/dist/purify.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-dom/dist/hmpl-dom.min.js"&gt;&lt;/script&gt; &lt;script&gt; document.addEventListener("click", async (e) =&gt; { const item = e.target.closest("[data-id]"); if (item) { const id = item.dataset.id; const html = await (await fetch("/api/product/" + id)).text(); detail.innerHTML = html; info.textContent = detail.querySelector("[data-hateoas]")?.textContent || "none"; } const back = e.target.closest("[data-back]"); if (back) { const html = await (await fetch(back.dataset.back)).text(); list.innerHTML = html; detail.innerHTML = ""; } }); &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; As a result, our application is located in about 120 lines and this is what it looks like: As you can see, thanks to hmpl-js and HATEOAS architecture, we can create cool and functional applications in just a few dozen lines of code, and this application works very flexibly with a mock server, since we do not set strict routes. ✅ Conclusion In this article, we discussed the HATEOAS architecture and created a small application using it. In fact, this topic receives little attention in application development, which is undeserved, as application flexibility allows us to create more scalable and easily maintainable websites. Thank you very much for reading this article ❤️! What do you think of this architecture? Have you ever used it in your own projects or seen it in work projects? It will be interesting to know in the comments! P.S. Also, don’t forget to give HMPL a star!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How The iframe Tag Changed The World</title><link href="https://blog.hmpl-lang.dev/2025/10/14/how-the-iframe-tag-changed-the-world/" rel="alternate" type="text/html" title="How The iframe Tag Changed The World" /><published>2025-10-14T20:00:00+00:00</published><updated>2025-10-14T20:00:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/10/14/how-the-iframe-tag-changed-the-world</id><author><name>HMPL Team</name></author><category term="blog" /><category term="webdev" /><category term="html" /><summary type="html"><![CDATA[Many things we are accustomed to in programming today were once unimaginable. In this article, we’ll talk about one such thing: the iframe. Many people know what it is, of course, and some may have forgotten, but at one time, it was a true miracle. Let’s dive a little into the history of the web and see what was there 🔎 🕸️ Web 1.0 With the advent of the modern internet in 1991 (www), its ubiquity was just beginning. Back then, it was a novelty that computers could communicate with each other. Everything hinged on local area networks (LANs) connecting computers in a single factory, bank, or other location. While it was understandable that two computers connected by wire could transfer files, it was difficult to do so even across the street. Back then, computers were incredibly expensive, like houses, but every year their cost became less and less, and ordinary people, not multi-billion dollar companies, could afford simple computers at that time. Back then, the internet was just gaining momentum, slowly but surely, and people were exchanging simple documents stored on domains. The first browsers were appearing, and people realized this was the future. Many businesses back then, launching their own simple websites, were able to attract as many customers as they could have from newspapers or television, given their budgets. It is precisely because of people’s desire to earn more that the second stage begins, when the first money appears on websites. 🌐 The Beginning of the Internet Bubble With the onset of this period in 1995, everyone began to believe that this was the future. This was true, but economically, there were questions: was it worth spending so much on an online business? But we’re only just beginning. Millions were spent sponsoring their websites. Everyone wanted to stand out somehow, to do something new. Let’s get right to the topic of advertising. Back then, it was similar to what you see in old newspapers today. Plain text, maybe an image at most (the img tag was introduced in 1993). It worked back then, but, as you can imagine, it wasn’t entirely effective, as it was unnoticeable and crude. People contrived everything they could, creating various images with text, using terrible color combinations, incomprehensible fonts, and so on. But it seemed perfectly natural back then, as there were no other options, and the work of a web designer as such was just beginning. There was no Figma back then, so :) 🌌 The appearance of the iframe tag It would seem that the img tag would be sufficient for advertising at the time. No one could have imagined that it would be possible to display an entire website on another website. But in 1997, it became possible. Imagine, now a client couldn’t just click on something, but also interact with it like on any other website! That is, you could now create an ad in the form of a game, say, tic-tac-toe, and instead of tic-tac-toe, you could use vacuum cleaners. You can also watch videos. This is a later development, but it’s still possible today. It became possible not in 1997, but a little later. Back then, people used Flash Player, but this topic is now so extensive that it deserves another article. ✅ Conclusion The influence of iframe is truly difficult to exaggerate, as it essentially created a new direction on the internet, one that gave rise to a new wave of advertising as an art, and gaming. Just look at the Flash Player and the majority of games that use it, which many still remember. I hope this article has covered some of this. Thank you very much everyone for reading the article!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Write Reactive HTML Without JavaScript</title><link href="https://blog.hmpl-lang.dev/2025/10/11/hmpl-dom-write-reactive-html-without-javascript/" rel="alternate" type="text/html" title="Write Reactive HTML Without JavaScript" /><published>2025-10-11T20:00:00+00:00</published><updated>2025-10-11T20:00:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/10/11/hmpl-dom-write-reactive-html-without-javascript</id><author><name>HMPL Team</name></author><category term="blog" /><category term="webdev" /><category term="javaScript" /><category term="opensource" /><category term="programming" /><summary type="html"><![CDATA[Hello! This is not clickbait. I thought for a long time about what to call this article, but it is hard to convey in words what is felt. Therefore, I wrote simply as I felt. For a long year we have been supplementing the template language, but the range of applied use was quite limited. We developed within the framework of the template paradigm, but, in essence, it was correct, but in an applied project it is still quite difficult to implement this without something serious. By serious I mean a framework, or something like that, that supported the syntax by default, but, in fact, if jsx has react, then it is quite difficult to build a structure on it, since it itself is structural. Therefore, we took a different path, which I will try to describe in this article. Structural Modules and the Real DOM Whatever anyone says, the time of template languages ​​is a bit different. Today, many people look at artificial intelligence as something breakthrough. And it is, but the fact is that it is not everything in our world. About 10 years ago, there was active development of various template languages, but now you are more likely to find 1000 new AI projects than one with templates. And this is not surprising, because with the advent of jsx, ejs and handlebars, we can consider that this topic has exhausted itself and humanity can no longer come up with anything better. Maybe it is so, but only in some aspects. We interact with the server in the same way, and php to js, ​​no matter how much you want, you can’t normally attach it. So, as an experiment, we created this project to move this topic forward. &lt;div class="container"&gt; &lt;p&gt;Loading...&lt;/p&gt; &lt;/div&gt; HTMX, no matter what SEO techniques they use and how caricatured they are in some sense, have nevertheless proven over 10-12 years of work on the topic that this topic is truly relevant in development. Together with Alpine.js, we see that not all people want to work on frameworks. This is correct, but it is also difficult and cumbersome on the other hand. This topic, for some reason, was actively developed in attributes 3-4 years ago, but for some reason no one looks at template languages. It’s as if the hype on them passed 10 years ago and everyone thinks that they are relics of the past, but this is not so. We believe that this topic is not forgotten, but we cannot deny the fact that today most of such projects are based on working with the real DOM. There is simply no escape from this. Hype on Attributes Anyone who thinks that in the world of development hype can be out of nowhere is wrong. Today, there are facts that in the state of the market today, people are not ready to switch to something more monumental, since it is easier to sit down at the framework. Therefore, working with the real DOM, when we connect only a couple of files - this is important. If you remember the same Docsify, to create documentation you do not need to install a bunch of packages that are not related to JS at all, as is done with Jekyll, this is the whole point. Therefore, no matter how much we develop the theme of the template language, in a vacuum it is quite difficult to use, therefore, in fact, an obvious decision was made to supplement the functionality with a new module, which is called hmpl-dom. &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Example&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;template hmpl&gt; &lt;div&gt; &lt;p class="indicator"&gt;Loading...&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/dompurify/dist/purify.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-dom/dist/hmpl-dom.min.js"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; Thanks to him, we combined the approach of a template language with working with a real DOM. I am convinced that attributes by definition, no matter how extensible they seem (like in Alpine.js, when you write expressions with functions there), they cannot be a full-fledged replacement. Yes, they have their advantages, but it’s not about them, it’s about working with the real DOM without js. What if I need to pass RequestInit? No one will move away from js, even in such an implementation. Its meaning is in the choice of using js or not, as well as in the simplicity that is currently on the market. index.html &lt;template data-hmpl data-config-id="clicker-config"&gt; &lt;div&gt; &lt;button data-action="increment" id="btn"&gt;Click!&lt;/button&gt; &lt;div&gt; Clicks: &lt;/div&gt; &lt;/div&gt; &lt;/template&gt; script.js import { init } from "hmpl-dom"; init([ { id: "clicker-config", value: { compile: { memo: true }, templateFunction: ({ request: { event } }) =&gt; ({ body: JSON.stringify({ action: event.target.getAttribute("data-action") }) }) } } ]); We can still pass everything that was done before. It’s just another level of nesting, when we had it before only within one compile function, now in a whole connected chain of templates, where a separate templateFunction is created for each (yes, we wouldn’t take outerHTML from the entire page, because that would be just stupid. Links More about this project you can find here: Repo Documentation Page Also, if you want to support us, you can put a star on our main project. Thanks! This article is based on the original tutorial by Anthony Max, available on Dev.to.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Reactive HTML Without JavaScript Frameworks</title><link href="https://blog.hmpl-lang.dev/2025/07/07/reactive-html-without-javascript-frameworks/" rel="alternate" type="text/html" title="Reactive HTML Without JavaScript Frameworks" /><published>2025-07-07T14:10:00+00:00</published><updated>2025-07-07T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/07/07/reactive-html-without-javascript-frameworks</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="JavaScript" /><category term="reactive" /><category term="frameworks" /><category term="performance" /><category term="web-development" /><category term="HTML" /><category term="lightweight" /><summary type="html"><![CDATA[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. The Problem with JavaScript Frameworks 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: Common Framework Issues Boilerplate Code: Developers often write repetitive setup code before implementing actual features Overly Complex Architecture: Frameworks impose their own architecture that can be too complex for simple projects Performance Overhead: Large runtime libraries bundle unnecessary code Vendor Lock-in: Makes it harder to switch technologies later Bundle Size: Many projects use only a fraction of a framework’s features yet pay the full cost For smaller applications, a lightweight alternative like HMPL.js can often achieve reactivity without unnecessary bloat. The HMPL.js Solution 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. Key Benefits Minimal Client Code: Only a few kilobytes of JavaScript Server-Oriented: Components are rendered on the server and loaded dynamically No Framework Dependencies: Pure HTML with lightweight HMPL.js Reusable Components: Components can be shared across different web applications Getting Started with HMPL.js Let’s look at a simple example that demonstrates how to create reactive HTML without heavy frameworks: &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Reactive HTML Example&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;template hmpl&gt; &lt;div&gt; &lt;p class="indicator"&gt;Header loading error&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;div class="content"&gt;&lt;/div&gt; &lt;template hmpl&gt; &lt;div&gt; &lt;p class="indicator"&gt;Footer loading error&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/dompurify/dist/purify.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-dom/dist/hmpl-dom.min.js"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; How It Works Server-Side Components: Your components are stored as HTML files on the server Dynamic Loading: HMPL.js fetches components from the server when needed Error Handling: Built-in error indicators for failed requests Minimal Dependencies: Only requires a few lightweight libraries Server-Side Implementation On your server, you can serve components as simple HTML files: /api/header.html &lt;header class="site-header"&gt; &lt;nav&gt; &lt;a href="/"&gt;Home&lt;/a&gt; &lt;a href="/about"&gt;About&lt;/a&gt; &lt;a href="/contact"&gt;Contact&lt;/a&gt; &lt;/nav&gt; &lt;/header&gt; /api/footer.html &lt;footer class="site-footer"&gt; &lt;p&gt;&amp;copy; 2025 Your Website. All rights reserved.&lt;/p&gt; &lt;/footer&gt; Advanced Features Reactive Data Binding HMPL.js supports reactive data binding without the complexity of full frameworks: &lt;template hmpl&gt; &lt;div&gt; &lt;div class="user-profile"&gt; &lt;h2&gt;&lt;/h2&gt; &lt;p&gt;&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/template&gt; Event Handling You can handle user interactions with simple event listeners: &lt;button onclick="updateProfile()"&gt;Update Profile&lt;/button&gt; &lt;script&gt; function updateProfile() { // HMPL.js will automatically re-render the component hmpl.request('/api/user-profile.html', { userId: 123 }); } &lt;/script&gt; Performance Benefits Bundle Size Comparison Framework Bundle Size HMPL.js Vue.js ~33KB ~5KB Angular ~135KB ~5KB Loading Performance Initial Load: Only loads essential HMPL.js libraries Component Loading: Components are loaded on-demand Caching: Server-side components can be cached effectively SEO Friendly: Content is available to search engines When to Use HMPL.js Perfect For: Simple to Medium Applications: Where full frameworks are overkill Content-Heavy Sites: Blogs, documentation, marketing sites Prototypes: Quick development without framework setup Legacy Integration: Adding reactivity to existing HTML sites Consider Alternatives When: Complex State Management: Applications with complex state requirements Real-time Features: Applications requiring WebSocket connections Large Teams: Teams already invested in specific frameworks Comparison with Other Solutions vs. HTMX HMPL.js: More focused on component-based architecture HTMX: Better for full-page updates and form handling vs. Alpine.js HMPL.js: Server-oriented with minimal client code Alpine.js: Client-side reactivity with more JavaScript vs. Vanilla JavaScript HMPL.js: Provides structure and conventions Vanilla JS: Complete freedom but requires more boilerplate Best Practices 1. Component Organization /api/ ├── header.html ├── footer.html ├── sidebar.html └── components/ ├── user-card.html └── product-list.html 2. Error Handling Always include error indicators in your templates: &lt;p class="error"&gt;Failed to load component&lt;/p&gt; &lt;p class="loading"&gt;Loading...&lt;/p&gt; 3. Performance Optimization Cache Components: Use server-side caching for frequently accessed components Minimize Requests: Group related components when possible Lazy Loading: Load components only when needed Conclusion 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. By carefully evaluating project needs, developers can choose the right balance between functionality and simplicity, avoiding over-engineering while still delivering dynamic user experiences. Key Takeaways Server-Oriented Approach: Components are rendered on the server and loaded dynamically Minimal Client Code: Only a few kilobytes of JavaScript required No Framework Lock-in: Pure HTML with lightweight HMPL.js Better Performance: Smaller bundle sizes and faster loading SEO Friendly: Content is available to search engines HMPL.js represents a practical middle ground between full frameworks and vanilla JavaScript, providing the reactivity you need without the complexity you don’t. This article is based on the original tutorial by Anthony Max, available on Dev.to.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Best Alpine.js Alternative</title><link href="https://blog.hmpl-lang.dev/2025/05/03/best-alpinejs-alternative/" rel="alternate" type="text/html" title="Best Alpine.js Alternative" /><published>2025-05-03T11:10:00+00:00</published><updated>2025-05-03T11:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/05/03/best-alpinejs-alternative</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="Alpine.js" /><category term="JavaScript" /><category term="comparison" /><category term="web-development" /><category term="alternatives" /><category term="frontend" /><summary type="html"><![CDATA[In this article I’ll tell you about a great replacement for Alpine.js that will help you do the same (and even more) with server-side HTML. A couple of months ago I wrote a similar article about HTMX, and now I can finally write about the benefits you can get by using HMPL instead of Alpine.js. In my opinion, this idea has much greater potential than what has been done so far. Well, let’s get started! How will we compare? First of all, all comparison will be in the context of the server connection. We will not consider options for regular client functionality here. Although everything is done on the client, there are still serious differences. We will consider the following parameters when comparing: Rendering Customization of server requests Disk space What’s under the hood of the modules We will also touch on the topic of support, ease of installation and a couple of other points. Rendering In modern web development, the choice of interface rendering approach plays a key role. We will consider two fundamentally different methods: template compilation in HMPL and the declarative approach of Alpine.js. HMPL HMPL uses client-side template compilation: const templateFn = hmpl.compile(` &lt;div&gt; {{#request src="/api/my-component" indicators=[ { trigger: "pending" content: "&lt;p&gt;Loading...&lt;/p&gt;" } ]}} {{/request}} &lt;/div&gt; `); // Usage const component = templateFn(); Alpine.js Alpine.js offers a declarative style: &lt;div x-data="{ user: null, loading: true }" x-init="fetch('/api/user') .then(r =&gt; r.json()) .then(data =&gt; { user = data; loading = false; })" &gt; &lt;template x-if="loading"&gt; &lt;div&gt;Loading...&lt;/div&gt; &lt;/template&gt; &lt;div x-show="user" class="user-card"&gt; &lt;h2 x-text="user.name"&gt;&lt;/h2&gt; &lt;span x-show="user.isPremium" class="badge"&gt;Premium&lt;/span&gt; &lt;/div&gt; &lt;/div&gt; Customization of server requests Efficiently managing server requests is crucial for dynamic web applications. Alpine.js Example: &lt;div x-data="{ user: null, error: null }" x-init="fetch('/api/user') .then(r =&gt; r.json()) .then(data =&gt; user = data) .catch(e =&gt; error = e)" &gt;&lt;/div&gt; HMPL Example: const elementObj = templateFn(({ request: { event, clearInterval } }) =&gt; { clearInterval?.(); return { mode: "cors", cache: "no-cache", credentials: "same-origin", headers: { "Content-Type": "text/html" }, redirect: "follow", get: (prop, value) =&gt; {}, referrerPolicy: "no-referrer", body: new FormatData(event.target, event.submitter) }; }); Disk space Alpine.js: document.querySelector("#app").innerHTML = `&lt;div x-data="{ count: 0, l() { fetch('/a').then(r =&gt; r.text()).then(d =&gt; this.c = d)}}"&gt;&lt;button @click="l()"&gt;Click!&lt;/button&gt;&lt;div&gt;Clicks: &lt;span x-text="c"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;`; HMPL: document .querySelector("#app") .append( hmpl.compile( `&lt;div&gt;&lt;button&gt;Click!&lt;/button&gt;&lt;div&gt;Clicks: {{#r src="/api/clicks" after="click:button" }}{{/r}}&lt;/div&gt;&lt;/div&gt;` )().response ); What’s under the hood Alpine.js supports both fetch and XMLHTTPRequest: &lt;div x-data="{ data: null }" x-init=" const xhr = new XMLHttpRequest(); xhr.overrideMimeType('text/html'); xhr.open('GET', '/api/data'); xhr.onload = () =&gt; { data = JSON.parse(xhr.responseText) }; xhr.send(); " &gt; &lt;div x-text="data?.message || 'Loading...'"&gt;&lt;/div&gt; &lt;/div&gt; HMPL uses only fetch: &lt;div&gt; &lt;button data-action="increment" id="btn"&gt;Click!&lt;/button&gt; &lt;div&gt; Clicks: {{#request src="/api/clicks" after="click:#btn" }}{{/request}} &lt;/div&gt; &lt;/div&gt; Conclusion Both options have their strengths. For server requests specifically, HMPL is more tailored for this task, while Alpine.js works well as a lightweight framework. Links to modules: HMPL GitHub Alpine.js GitHub Thank you all very much for reading the article!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Client‑Side SSR: Build a Component‑Based Landing Page in 10 Minutes</title><link href="https://blog.hmpl-lang.dev/2025/04/27/client-side-ssr-build-a-component-based-landing-page-in-10-minutes/" rel="alternate" type="text/html" title="Client‑Side SSR: Build a Component‑Based Landing Page in 10 Minutes" /><published>2025-04-27T14:10:00+00:00</published><updated>2025-04-27T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/04/27/client%E2%80%91side-ssr-build-a-component%E2%80%91based-landing-page-in-10-minutes</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="SSR" /><category term="components" /><category term="landing-page" /><category term="tutorial" /><category term="web-development" /><category term="JavaScript" /><category term="quick-start" /><summary type="html"><![CDATA[Client‑Side SSR: Build a Component‑Based Landing Page in 10 Minutes⏱️ Today, it is impossible to imagine a modern large project without using Next.js or Nuxt.js. But, nevertheless, if the task is to quickly create such a structure, then this method, which is described here, is perfect for this. Today, we will create a small landing page application with 5 components that are located on the server. Let’s get started! Application structure Our application will have a structure just like modern SSR applications (without BFF, of course, etc.), but the rendering will occur on the client, which is shown through the browser. There is no concept of a database in our structure, since the data will be located in HTML files. But if we were doing registration on the landing page, we might include a .json file; however, this example is meant to be built in 10 minutes, so we’ll keep it simple. To connect the client to the server, we’ll use the HMPL module. Where to start creating an app? Create two files: global.css and global.js. These will include the styles and scripts independent of server-rendered components. global.css * { margin: 0; padding: 0; box-sizing: border-box; font-family: Roboto, sans-serif; } body { line-height: 1.6; color: #333; } .container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 20px; } .section { padding: 80px 0; text-align: center; } .section h2 { font-size: 36px; margin-bottom: 30px; } global.js console.log("Global scripts loaded"); Now, create index.html and link the necessary modules: &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;My Landing Page&lt;/title&gt; &lt;link rel="stylesheet" href="global.css" /&gt; &lt;/head&gt; &lt;body&gt; &lt;script src="https://unpkg.com/json5/dist/index.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/dompurify/dist/purify.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script src="global.js"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; ⚙️ Server Configuration We’ll use Node.js with Express.js for the server. app.js const express = require("express"); const path = require("path"); const bodyParser = require("body-parser"); const cors = require("cors"); const PORT = 8000; const app = express(); const getRoutes = require("./routes/get"); app.use(express.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cors({ origin: true, credentials: true })); app.use(express.static(path.join(__dirname, "src"))); app.get("/", (_, res) =&gt; { res.sendFile(path.join(__dirname, "src/index.html")); }); app.use("/api", getRoutes); app.listen(PORT, () =&gt; { console.log(`Server is running on http://localhost:${PORT}`); }); routes/get.js const express = require("express"); const expressRouter = express.Router(); const path = require("path"); const components = { title: "CTA", header: "Header", features: "Features", promo: "Promo", cta: "CTA", footer: "Footer", }; Object.entries(components).forEach(([name, folder]) =&gt; { expressRouter.get(`/get-${name}-component`, (_, res) =&gt; { res.type("text/html"); res.sendFile(path.join(__dirname, `../components/${folder}/index.html`)); }); }); module.exports = expressRouter; ⌨️ Writing the first component Create the features section, accessible via: http://localhost:8000/api/get-features-component components/Features/index.html &lt;div id="features-component"&gt; &lt;section id="features" class="section features"&gt; &lt;div class="container"&gt; &lt;h2&gt;Our Amazing Features&lt;/h2&gt; &lt;div class="features-grid"&gt; &lt;div class="feature-card"&gt; &lt;h3&gt;Fast&lt;/h3&gt; &lt;p&gt;Lightning fast performance that saves you time.&lt;/p&gt; &lt;/div&gt; &lt;div class="feature-card"&gt; &lt;h3&gt;Simple&lt;/h3&gt; &lt;p&gt;Easy to use interface with no learning curve.&lt;/p&gt; &lt;/div&gt; &lt;div class="feature-card"&gt; &lt;h3&gt;Reliable&lt;/h3&gt; &lt;p&gt;99.9% uptime guaranteed for your business.&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/section&gt; &lt;style&gt; .features { background: #f9f9f9; padding: 80px 0; text-align: center; } .features h2 { font-size: 36px; margin-bottom: 30px; } .features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; margin-top: 50px; } .feature-card { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); opacity: 0; transform: translateY(20px); transition: all 0.6s ease; } .feature-card h3 { margin-bottom: 15px; font-size: 22px; } @media (max-width: 768px) { .features-grid { grid-template-columns: 1fr; } } &lt;/style&gt; &lt;script&gt; const animateFeatures = function () { const elements = document.querySelectorAll( "#features-component .feature-card" ); elements.forEach((element) =&gt; { const elementPosition = element.getBoundingClientRect().top; const screenPosition = window.innerHeight / 1.3; if (elementPosition &lt; screenPosition) { element.style.opacity = "1"; element.style.transform = "translateY(0)"; } }); }; window.addEventListener("load", animateFeatures); window.addEventListener("scroll", animateFeatures); &lt;/script&gt; &lt;/div&gt; ✅ Writing the rest Repeat similar steps for the remaining components: Header: /api/get-header-component Promo: /api/get-promo-component CTA: /api/get-cta-component Footer: /api/get-footer-component All component files are available in the linked repository. Connecting everything to index.html Append components dynamically using HMPL: &lt;script&gt; const body = document.querySelector("body"); const template = ` &lt;main&gt; {{#request src="http://localhost:8000/api/get-header-component"}}{{/request}} {{#request src="http://localhost:8000/api/get-features-component"}}{{/request}} {{#request src="http://localhost:8000/api/get-promo-component"}}{{/request}} {{#request src="http://localhost:8000/api/get-cta-component"}}{{/request}} {{#request src="http://localhost:8000/api/get-footer-component"}}{{/request}} &lt;/main&gt; `; const { response } = hmpl.compile(template)(); body.append(response); &lt;/script&gt; You can also use interval for repeated fetching or add loaders. ️ Result The result is a functioning landing page built client-side in just ten minutes — clean, dynamic, and modular. ️ Conclusion We built a small, yet sleek and functional landing page using client‑side SSR in under 10 minutes. This method offers a lightweight alternative to heavy frameworks like Next.js or Nuxt.js, especially when SEO isn’t critical. Feel free to show some ❤️ and star the project if you found this helpful! ️ Repository link Full source code and all components are available here: https://github.com/hmpl-language/examples/tree/main/landing]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to reduce web application bundle size?</title><link href="https://blog.hmpl-lang.dev/2025/02/27/how-to-reduce-web-application-bundle-size/" rel="alternate" type="text/html" title="How to reduce web application bundle size?" /><published>2025-02-27T14:10:00+00:00</published><updated>2025-02-27T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/02/27/how-to-reduce-web-application-bundle-size</id><author><name>HMPL Team</name></author><category term="blog" /><summary type="html"><![CDATA[Often, when working on a project for a long time, you notice that the more functionality you add, the slower the web application becomes. Although, it would seem that there is no point in adding a table, a button, or something else that in some vacuum weighs quite a bit. As a result, you get an unacceptable initial load, which can take more than 10-30 seconds, for example. In this article, I would like to consider some methods and little tricks that will help you avoid this and make your site as fast to load and smaller in size as possible. Platform Dependency If you want to reduce the size of a web application, then first of all you need to start with the platform you use for the base. If we take Next.js, then these are some methods, but if these are self-written sites, then these are slightly different. Therefore, first of all, it is worth looking for how to configure the same framework or library so that they give a better result, changing just a couple of settings, for example, the same caching of responses to requests to the server, or an add-on for images - all this is sometimes already built into the config itself, all that remains is to find it. Migration from CSR to SSR (SSG, ISG, etc.) One of the best ways to reduce the size of a bundle is to transfer the rendering of parts of a page from the client to the server. This allows you to get a kind of framework, where the component will be loaded brick by brick. Accordingly, the size of the HTML and JS source files of such a project will consist only of empty tags and requests to the server, which put ready-made components there. An example of such an approach is the following code: index.html &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;&lt;%= data.title %&gt;&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;&lt;%= data.title %&gt;&lt;/h1&gt; &lt;p&gt;&lt;%= data.content %&gt;&lt;/p&gt; &lt;/body&gt; &lt;/html&gt; server.js const express = require("express"); const app = express(); const PORT = 3000; // Set EJS as the templating engine app.set("view engine", "ejs"); // Sample data const data = { title: "Server Side Rendering Example", content: "This is an example of Server Side Rendering using Node.js and EJS." }; // Define a route app.get("/", (req, res) =&gt; { // Render the HTML using EJS res.render("index", { data }); }); // Start the server app.listen(PORT, () =&gt; { console.log(`Server is running on http://localhost:${PORT}`); }); Here we see that thanks to EJS and Express we can render everything on the server. Also, we can redesign the site for Next.js, then we will achieve a similar effect not only for one page, but also for others, including with dynamic routes, and, of course, indexing by robots. BUT, this method of making SSR (SSG, ISG etc.) has serious disadvantages, because of which it may not be suitable. For example, if the site is already on some of the frameworks or libraries, which was already focused on the client side, then redoing everything can cost a lot of money and time. Also, the specifics of choosing such tools (except Next.js) can provoke a shortage of personnel who are suitable for these tasks. If a person learned to work on one framework, and the vacancy is not very popular, difficult to replace library, then finding an applicant will be problematic. To keep the server-oriented approach, and at the same time not have significant problems described above, you can use HMPL.js or similar libraries. Implementing Server-Oriented Methods Using HMPL.js Unlike the methods described above, the module will not allow robots to index the page, but you can connect it to any web application, or simply to any site, be it WordPress, Vue.js, Tilda, Next.js, or wherever you want. Working with the module looks something like this: index.html &lt;main id="app"&gt;&lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; client.js const templateFn = hmpl.compile( `&lt;div&gt; &lt;button data-action="increment" id="btn"&gt;Click!&lt;/button&gt; &lt;div&gt;Clicks: &lt;/div&gt; &lt;/div&gt;` ); const clicker = templateFn(({ request: { event } }) =&gt; ({ body: JSON.stringify({ action: event.target.getAttribute("data-action") }) })).response; document.querySelector("#app").append(clicker); Here, we also get rendered HTML, but we don’t have a clear architecture to adhere to. We can either disable or enable the module for any project and there will be no consequences. It is also easy to use, because it consists of a small, but necessary number of functional capabilities. Also, in the example, you can safely remove after and load components during DOM rendering. Other general methods that can help reduce bundle size Here, if we do not take work with the server, but just regular work with the web application, then the methods described below can also help in reducing the bundle size: 1. Removing unnecessary dependencies It happens that in the process of developing a web application you need to create some functionality and you download different packages, trying them out, choosing the most suitable for the task. Forgetting to delete them, the size of the bundle, accordingly, only becomes larger. Or, if a huge module is connected to a task that can be solved in regular js and one function is used from there - this is also simply pointless. To analyze unused packages, for example, you can use the following package or something similar: npm install depcheck depcheck /path/to/my/project or npx depcheck This module, although not supported, will still allow you to analyze dependencies and identify unused ones. But, you need to use it carefully, because it would seem that something is not used, but then without it some module will not work - this also needs to be controlled. You can also use npm’s built-in functionality via the following command: npm prune This command removes “extraneous” packages. If a package name is provided, then only packages matching one of the supplied names are removed. 2. Using lower sized media files in a project This is probably one of the simplest and most obvious pieces of advice that can be given. If you have a single video in your project that is equal in size to the entire web application, then it will be simply difficult to work with, let’s say, with the same git clone. This practice is great for images, where you can save a few MB per image without losing any quality. Online compression platforms can easily do this today. Also, you can change the image resolution from png, jpg to webp. This is also a good practice, which is used in many large web applications. 3. Using CDN This is also one of the common ways when you transfer a module from npm_modules to an external environment. import { chunk } from "lodash"; or &lt;script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"&gt;&lt;/script&gt; It is somewhat similar to what was described earlier, but has a slightly different meaning. 4. Code splitting One of the easiest ways to split code is to use dynamic imports. In modern bundlers like Webpack and Vite, you can easily write something like this: main.js document.getElementById("loadButton").addEventListener("click", () =&gt; { import("./module.js") .then((module) =&gt; { module.default(); }) .catch((err) =&gt; { console.error("Error loading the module:", err); }); }); In this case, we do not load the module immediately, but only when necessary, when the button is pressed. You can also enable chunk splitting. This is useful for separating common code between different modules. webpack.config.js module.exports = { optimization: { splitChunks: { chunks: "all" } } }; 5. Code minification You can also reduce the bundle size if you apply minification during compilation to your code. This is probably one of the best ways you can use. uglifyjs file.js -c toplevel,sequences=false For this, you can use Uglify.js, which is one of the most popular tools for code minification. It can also be used with bundlers, if it or similar ones are not included by default, of course. Conclusion First of all, from all the listed, I tried to describe the most general methods that are applicable to almost every web application. They are the most popular of those that are always taken up when setting such a task. I also did not want to write some stupid advice about DRY, KISS principles, which are already obvious in terms of reducing code, I wanted more specifics. But, in any case, I hope that these methods will help you make your site smaller and faster! Thank you very much for reading the article!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to reduce web application bundle size?</title><link href="https://blog.hmpl-lang.dev/2025/02/27/how-to-reduce-web-application-bundle-size/" rel="alternate" type="text/html" title="How to reduce web application bundle size?" /><published>2025-02-27T14:10:00+00:00</published><updated>2025-02-27T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/02/27/how-to-reduce-web-application-bundle-size</id><author><name>HMPL Team</name></author><category term="blog" /><category term="Performance" /><category term="Optimization" /><category term="Bundle-size" /><category term="web-development" /><category term="JavaScript" /><category term="SSR" /><category term="CSR" /><summary type="html"><![CDATA[Often, when working on a project for a long time, you notice that the more functionality you add, the slower the web application becomes. Although, it would seem that there is no point in adding a table, a button, or something else that in some vacuum weighs quite a bit. As a result, you get an unacceptable initial load, which can take more than 10-30 seconds, for example. In this article, I would like to consider some methods and little tricks that will help you avoid this and make your site as fast to load and smaller in size as possible. Platform Dependency If you want to reduce the size of a web application, then first of all you need to start with the platform you use for the base. If we take Next.js, then these are some methods, but if these are self-written sites, then these are slightly different. Therefore, first of all, it is worth looking for how to configure the same framework or library so that they give a better result, changing just a couple of settings, for example, the same caching of responses to requests to the server, or an add-on for images - all this is sometimes already built into the config itself, all that remains is to find it. Migration from CSR to SSR (SSG, ISG, etc.) One of the best ways to reduce the size of a bundle is to transfer the rendering of parts of a page from the client to the server. This allows you to get a kind of framework, where the component will be loaded brick by brick. Accordingly, the size of the HTML and JS source files of such a project will consist only of empty tags and requests to the server, which put ready-made components there. An example of such an approach is the following code: index.html &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;&lt;%= data.title %&gt;&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;&lt;%= data.title %&gt;&lt;/h1&gt; &lt;p&gt;&lt;%= data.content %&gt;&lt;/p&gt; &lt;/body&gt; &lt;/html&gt; server.js const express = require("express"); const app = express(); const PORT = 3000; // Set EJS as the templating engine app.set("view engine", "ejs"); // Sample data const data = { title: "Server Side Rendering Example", content: "This is an example of Server Side Rendering using Node.js and EJS." }; // Define a route app.get("/", (req, res) =&gt; { // Render the HTML using EJS res.render("index", { data }); }); // Start the server app.listen(PORT, () =&gt; { console.log(`Server is running on http://localhost:${PORT}`); }); Here we see that thanks to EJS and Express we can render everything on the server. Also, we can redesign the site for Next.js, then we will achieve a similar effect not only for one page, but also for others, including with dynamic routes, and, of course, indexing by robots. BUT, this method of making SSR (SSG, ISG etc.) has serious disadvantages, because of which it may not be suitable. For example, if the site is already on some of the frameworks or libraries, which was already focused on the client side, then redoing everything can cost a lot of money and time. Also, the specifics of choosing such tools (except Next.js) can provoke a shortage of personnel who are suitable for these tasks. If a person learned to work on one framework, and the vacancy is not very popular, difficult to replace library, then finding an applicant will be problematic. To keep the server-oriented approach, and at the same time not have significant problems described above, you can use HMPL.js or similar libraries. Implementing Server-Oriented Methods Using HMPL.js Unlike the methods described above, the module will not allow robots to index the page, but you can connect it to any web application, or simply to any site, be it WordPress, Vue.js, Tilda, Next.js, or wherever you want. Working with the module looks something like this: index.html &lt;main id="app"&gt;&lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; client.js const templateFn = hmpl.compile( `&lt;div&gt; &lt;button data-action="increment" id="btn"&gt;Click!&lt;/button&gt; &lt;div&gt;Clicks: {{#request src="/api/clicks" after="click:#btn"}}{{/request}}&lt;/div&gt; &lt;/div&gt;` ); const clicker = templateFn(({ request: { event } }) =&gt; ({ body: JSON.stringify({ action: event.target.getAttribute("data-action") }) })).response; document.querySelector("#app").append(clicker); Here, we also get rendered HTML, but we don’t have a clear architecture to adhere to. We can either disable or enable the module for any project and there will be no consequences. It is also easy to use, because it consists of a small, but necessary number of functional capabilities. Also, in the example, you can safely remove after and load components during DOM rendering. Other general methods that can help reduce bundle size Here, if we do not take work with the server, but just regular work with the web application, then the methods described below can also help in reducing the bundle size: 1. Removing unnecessary dependencies It happens that in the process of developing a web application you need to create some functionality and you download different packages, trying them out, choosing the most suitable for the task. Forgetting to delete them, the size of the bundle, accordingly, only becomes larger. Or, if a huge module is connected to a task that can be solved in regular js and one function is used from there - this is also simply pointless. To analyze unused packages, for example, you can use the following package or something similar: npm install depcheck depcheck /path/to/my/project or npx depcheck This module, although not supported, will still allow you to analyze dependencies and identify unused ones. But, you need to use it carefully, because it would seem that something is not used, but then without it some module will not work - this also needs to be controlled. You can also use npm’s built-in functionality via the following command: npm prune This command removes “extraneous” packages. If a package name is provided, then only packages matching one of the supplied names are removed. 2. Using lower sized media files in a project This is probably one of the simplest and most obvious pieces of advice that can be given. If you have a single video in your project that is equal in size to the entire web application, then it will be simply difficult to work with, let’s say, with the same git clone. This practice is great for images, where you can save a few MB per image without losing any quality. Online compression platforms can easily do this today. Also, you can change the image resolution from png, jpg to webp. This is also a good practice, which is used in many large web applications. 3. Using CDN This is also one of the common ways when you transfer a module from npm_modules to an external environment. import { chunk } from "lodash"; or &lt;script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"&gt;&lt;/script&gt; It is somewhat similar to what was described earlier, but has a slightly different meaning. 4. Code splitting One of the easiest ways to split code is to use dynamic imports. In modern bundlers like Webpack and Vite, you can easily write something like this: main.js document.getElementById("loadButton").addEventListener("click", () =&gt; { import("./module.js") .then((module) =&gt; { module.default(); }) .catch((err) =&gt; { console.error("Error loading the module:", err); }); }); In this case, we do not load the module immediately, but only when necessary, when the button is pressed. You can also enable chunk splitting. This is useful for separating common code between different modules. webpack.config.js module.exports = { optimization: { splitChunks: { chunks: "all" } } }; 5. Code minification You can also reduce the bundle size if you apply minification during compilation to your code. This is probably one of the best ways you can use. uglifyjs file.js -c toplevel,sequences=false For this, you can use Uglify.js, which is one of the most popular tools for code minification. It can also be used with bundlers, if it or similar ones are not included by default, of course. Conclusion First of all, from all the listed, I tried to describe the most general methods that are applicable to almost every web application. They are the most popular of those that are always taken up when setting such a task. I also did not want to write some stupid advice about DRY, KISS principles, which are already obvious in terms of reducing code, I wanted more specifics. But, in any case, I hope that these methods will help you make your site smaller and faster! Thank you very much for reading the article!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Reactive HTML Without JavaScript Frameworks</title><link href="https://blog.hmpl-lang.dev/2025/01/27/reactive-html-without-javascript-frameworks/" rel="alternate" type="text/html" title="Reactive HTML Without JavaScript Frameworks" /><published>2025-01-27T14:10:00+00:00</published><updated>2025-01-27T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2025/01/27/reactive-html-without-javascript-frameworks</id><author><name>HMPL Team</name></author><category term="blog" /><summary type="html"><![CDATA[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. The Problem with JavaScript Frameworks 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: Common Framework Issues Boilerplate Code: Developers often write repetitive setup code before implementing actual features Overly Complex Architecture: Frameworks impose their own architecture that can be too complex for simple projects Performance Overhead: Large runtime libraries bundle unnecessary code Vendor Lock-in: Makes it harder to switch technologies later Bundle Size: Many projects use only a fraction of a framework’s features yet pay the full cost For smaller applications, a lightweight alternative like HMPL.js can often achieve reactivity without unnecessary bloat. The HMPL.js Solution 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. Key Benefits Minimal Client Code: Only a few kilobytes of JavaScript Server-Oriented: Components are rendered on the server and loaded dynamically No Framework Dependencies: Pure HTML with lightweight HMPL.js Reusable Components: Components can be shared across different web applications Getting Started with HMPL.js Let’s look at a simple example that demonstrates how to create reactive HTML without heavy frameworks: &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Reactive HTML Example&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;template hmpl&gt; &lt;div&gt; &lt;p class="indicator"&gt;Header loading error&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;div class="content"&gt;&lt;/div&gt; &lt;template hmpl&gt; &lt;div&gt; &lt;p class="indicator"&gt;Footer loading error&lt;/p&gt; &lt;/div&gt; &lt;/template&gt; &lt;/main&gt; &lt;script src="https://unpkg.com/json5/dist/index.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/dompurify/dist/purify.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-dom/dist/hmpl-dom.min.js"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; How It Works Server-Side Components: Your components are stored as HTML files on the server Dynamic Loading: HMPL.js fetches components from the server when needed Error Handling: Built-in error indicators for failed requests Minimal Dependencies: Only requires a few lightweight libraries Server-Side Implementation On your server, you can serve components as simple HTML files: /api/header.html &lt;header class="site-header"&gt; &lt;nav&gt; &lt;a href="/"&gt;Home&lt;/a&gt; &lt;a href="/about"&gt;About&lt;/a&gt; &lt;a href="/contact"&gt;Contact&lt;/a&gt; &lt;/nav&gt; &lt;/header&gt; /api/footer.html &lt;footer class="site-footer"&gt; &lt;p&gt;&amp;copy; 2025 Your Website. All rights reserved.&lt;/p&gt; &lt;/footer&gt; Advanced Features Reactive Data Binding HMPL.js supports reactive data binding without the complexity of full frameworks: &lt;template hmpl&gt; &lt;div&gt; &lt;div class="user-profile"&gt; &lt;h2&gt;&lt;/h2&gt; &lt;p&gt;&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/template&gt; Event Handling You can handle user interactions with simple event listeners: &lt;button onclick="updateProfile()"&gt;Update Profile&lt;/button&gt; &lt;script&gt; function updateProfile() { // HMPL.js will automatically re-render the component hmpl.request('/api/user-profile.html', { userId: 123 }); } &lt;/script&gt; Performance Benefits Bundle Size Comparison Framework Bundle Size HMPL.js Vue.js ~33KB ~5KB Angular ~135KB ~5KB Loading Performance Initial Load: Only loads essential HMPL.js libraries Component Loading: Components are loaded on-demand Caching: Server-side components can be cached effectively SEO Friendly: Content is available to search engines When to Use HMPL.js Perfect For: Simple to Medium Applications: Where full frameworks are overkill Content-Heavy Sites: Blogs, documentation, marketing sites Prototypes: Quick development without framework setup Legacy Integration: Adding reactivity to existing HTML sites Consider Alternatives When: Complex State Management: Applications with complex state requirements Real-time Features: Applications requiring WebSocket connections Large Teams: Teams already invested in specific frameworks Comparison with Other Solutions vs. HTMX HMPL.js: More focused on component-based architecture HTMX: Better for full-page updates and form handling vs. Alpine.js HMPL.js: Server-oriented with minimal client code Alpine.js: Client-side reactivity with more JavaScript vs. Vanilla JavaScript HMPL.js: Provides structure and conventions Vanilla JS: Complete freedom but requires more boilerplate Best Practices 1. Component Organization /api/ ├── header.html ├── footer.html ├── sidebar.html └── components/ ├── user-card.html └── product-list.html 2. Error Handling Always include error indicators in your templates: &lt;p class="error"&gt;Failed to load component&lt;/p&gt; &lt;p class="loading"&gt;Loading...&lt;/p&gt; 3. Performance Optimization Cache Components: Use server-side caching for frequently accessed components Minimize Requests: Group related components when possible Lazy Loading: Load components only when needed Conclusion 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. By carefully evaluating project needs, developers can choose the right balance between functionality and simplicity, avoiding over-engineering while still delivering dynamic user experiences. Key Takeaways Server-Oriented Approach: Components are rendered on the server and loaded dynamically Minimal Client Code: Only a few kilobytes of JavaScript required No Framework Lock-in: Pure HTML with lightweight HMPL.js Better Performance: Smaller bundle sizes and faster loading SEO Friendly: Content is available to search engines HMPL.js represents a practical middle ground between full frameworks and vanilla JavaScript, providing the reactivity you need without the complexity you don’t. This article is based on the original tutorial by Anthony Max, available on Dev.to.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Creating a Gallery App in JavaScript with HMPL</title><link href="https://blog.hmpl-lang.dev/2024/12/18/creating-a-gallery-app-in-javascript-with-hmpl/" rel="alternate" type="text/html" title="Creating a Gallery App in JavaScript with HMPL" /><published>2024-12-18T14:10:00+00:00</published><updated>2024-12-18T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/12/18/creating-a-gallery-app-in-javascript-with-hmpl</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="JavaScript" /><category term="web-development" /><category term="tutorial" /><category term="gallery" /><category term="image-gallery" /><category term="responsive-design" /><summary type="html"><![CDATA[Hello everyone! In this article I will describe the process of creating a Gallery application. You can safely take this application and edit it as you wish (you can only change the pictures there, because there is a license). It is small in functionality, but, in my opinion, it is quite suitable for an example of work. What does the application look like and what is its functionality? The application is a small list of images, the pages of which can be navigated. The interface looks like this: Desktop Mobile In terms of functionality, you can click the Next button and go to the next page, and by clicking the Previous button, you can return to the first page. Also, if you click on any of the images, you can see it in full format: This is the main functionality that is available in the application. Subtleties of the application One of the main features of this application is that the images, like the title text, come from the server. That is, we do not store 10 images in the site repository on the client. They all come from the server. This can be achieved by an approach where we store the HTML of the main content on the server, and on the client we output it to some cells, which, in essence, take up little space on the disk. Remember, when you clone files from a remote repository, cloning videos or images can take a lot of time when there is very little code there. The same is true here. This is one of the main advantages of such an application. Also, on the client in the browser, if we take the loading of the application, it can load for several seconds when the user first enters the site. He can close this resource and go to another, so in terms of money this can save you a budget in certain cases. This approach is server-oriented, but not server side rendering, since the components are rendered on the client and robots will not see the result. In any case, there is such a way to create a website today and it is quite convenient and has its advantages. Quite a lot of libraries today implement similar functionality. One of these is HMPL. The development process and the code itself First of all, you need to choose the platforms on which the application will be written. By platforms we mean Express.js for the backend, and in general Node.js, respectively, and on the client we will have a simple Webpack assembly. Client-side There are different approaches to where to start first. From the server or from the client. In our case, it would be better to start from the client, because on the server we know that the list of images and the title will already be generated, but how to best integrate them into the DOM - this is exactly what we need to figure out first. Let’s move on to the original HTML file: index.html &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Gallery App&lt;/title&gt; &lt;/head&gt; &lt;body&gt;&lt;/body&gt; &lt;/html&gt; It would seem that there is nothing here, and yes, you are right. Components that will be the content will be loaded into this file. We will create them in .hmpl extension files, which slightly expand the capabilities of html. To do this, we will create a components folder, where these files will be stored. We will connect each of them to the page via JavaScript. Their markup: Gallery.hmpl &lt;div&gt; &lt;div class="gallery-initial" id="gallery-initial"&gt; { { src: "http://localhost:8000/api/images", method: "POST" } } &lt;/div&gt; &lt;div class="gallery" id="gallery"&gt; { { src: "http://localhost:8000/api/images", after: "click:.navigation-button", method: "POST" } } &lt;/div&gt; &lt;div class="pagination"&gt; &lt;button class="navigation-button" data-page="1" id="previous" disabled&gt; Previous &lt;/button&gt; &lt;button class="navigation-button" data-page="2" id="next"&gt;Next&lt;/button&gt; &lt;/div&gt; &lt;div class="modal" id="modal"&gt; &lt;img src="https://raw.githubusercontent.com/hmpl-language/media/refs/heads/main/logo.png" alt="" /&gt; &lt;/div&gt; &lt;/div&gt; It is worth noting that there are two objects marked here. The first one is triggered when the page is loaded, while the second one is triggered after clicking on the navigation buttons. Title.hmpl &lt;h1 id="title"&gt;{{#request src="http://localhost:8000/api/title"}}{{/request}}&lt;/h1&gt; Here, the objects will be changed to HTML from the server. Now, they should be connected. To do this, import them into main.js: import "./index.scss"; import GalleryTemplate from "./components/Gallery/Gallery.hmpl"; import TitleTemplate from "./components/Title/Title.hmpl"; const { response: Title } = TitleTemplate(); const { response: Gallery } = GalleryTemplate(({ request: { event } }) =&gt; { return { headers: { "Content-Type": "application/json", }, body: JSON.stringify({ page: event ? Number(event.target.getAttribute("data-page")) : 1, }), }; }); document.body.append(Title); document.body.append(Gallery); const gallery = document.querySelector("#gallery"); const galleryInitial = document.querySelector("#gallery-initial"); const modal = document.querySelector("#modal"); const modalImg = modal.querySelector("img"); const navigationButtons = document.querySelectorAll(".navigation-button"); const setActive = (e) =&gt; { if (e.target.tagName === "IMG") { modalImg.src = e.target.src; modal.classList.add("active"); } }; modal.addEventListener("click", () =&gt; { modal.classList.remove("active"); }); galleryInitial.addEventListener("click", (e) =&gt; { setActive(e); }); gallery.addEventListener("click", (e) =&gt; { setActive(e); }); for (let i = 0; i &lt; navigationButtons.length; i++) { const btn = navigationButtons[i]; btn.addEventListener("click", () =&gt; { if (!galleryInitial.classList.contains("hidden")) galleryInitial.classList.add("hidden"); btn.setAttribute("disabled", ""); navigationButtons[i === 0 ? 1 : 0].removeAttribute("disabled"); }); } Also, in main.js we will describe the logic of the application. Here we send a request to the server and receive HTML, which we have not prepared yet, but will prepare during the development process. Since the server HTML is in the div block, we can easily add components to the DOM without waiting for a response. Here you need to add another switch between the disabled attribute for the buttons. Ideally, it would be worth getting the number of pages from the server and focusing on that, but since the application itself is small and all the constants are known in advance, it is better not to overload it with additional code. By the way, the image change itself will happen automatically, upon request to the API. And it will also be necessary to show the image on click - this is done by hanging an event on the wrapper tag and determining that if it is a click on the image, then the block must be made active accordingly. The styles we include look like this: index.scss body { font-family: Arial, sans-serif; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; background-color: #f4f4f4; } h1 { margin: 20px 0; color: #333; } .gallery-initial.active { display: flex; } .gallery, .gallery-initial { display: flex; gap: 20px; width: 90%; max-width: 1000px; @media (max-width:1023px) { display: grid; grid-template-columns: repeat(2, 1fr); max-width: unset; justify-content: center; align-items: center; width: 100%; } } .hidden { display: none; } .gallery img, .gallery-initial img { width: 150px; height: 100px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); cursor: pointer; transition: transform 0.2s; } .gallery img:hover, .gallery-initial img:hover { transform: scale(1.05); } .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); justify-content: center; align-items: center; } .modal img { max-width: 90%; max-height: 90%; border-radius: 10px; } .modal.active { display: flex; } .pagination { margin: 20px 0; display: flex; gap: 10px; align-items: center; justify-content: center; } .pagination button { padding: 10px 20px; border: none; background-color: #333; color: #fff; border-radius: 5px; cursor: pointer; transition: background-color 0.2s; } .pagination button:hover { background-color: #555; } .pagination button:disabled { background-color: #ccc; cursor: not-allowed; } The styles are minimal, just so that the gallery looks more or less presentable. Also, I usually use ready-made webpack assemblies that I made a long time ago (I had to make a website for the framework), but now there is no point in dwelling on each point of what is responsible for what in webpack.config.js. Now, it’s time to move on to the backend. Backend When creating a backend, we can now calmly look at the client and, based on this, create the routes needed for it. Let’s say I created a gallery - great, then I need to download the pictures and set up the route described there. We see that the route that needs to be created is /api/images: src: "http://localhost:8000/api/images", Now, for it, you just need to prepare the HTML markup that would be issued in response. Moreover, the method for the route will be POST, because in the body of RequestInit you need to pass page with the required value. Let’s set a similar route: routes/post.js const express = require("express"); const expressRouter = express.Router(); const imagePaths = [ "http://localhost:8000/images/img1.jpg", "http://localhost:8000/images/img2.jpg", "http://localhost:8000/images/img3.jpg", "http://localhost:8000/images/img4.jpg", "http://localhost:8000/images/img5.jpg", "http://localhost:8000/images/img6.jpg", "http://localhost:8000/images/img7.jpg", "http://localhost:8000/images/img8.jpg", "http://localhost:8000/images/img9.jpg", "http://localhost:8000/images/img10.jpg", ]; const imagesController = (req, res) =&gt; { const { page } = req.body; if (!page || isNaN(page)) { return res.status(400).send("Page number error"); } const pageNumber = parseInt(page); const itemsPerPage = 5; const startIndex = (pageNumber - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; if (startIndex &gt;= imagePaths.length || pageNumber &lt; 1) { return res.status(404).send("Page not found"); } const imagesForPage = imagePaths.slice(startIndex, endIndex); const htmlResponse = ` ${imagesForPage .map((img, index) =&gt; `&lt;img src="${img}" alt="Image${index}"/&gt;`) .join("\n")} `; res.send(htmlResponse); }; expressRouter.post("/images", imagesController); module.exports = expressRouter; It is important that we generate images dynamically, depending on the page. Also, it is worth noting that the path for the images will not be addressed to folders, but to the address itself. In the app.js file, we will do just this so that the images are loaded from the folder. Now, it’s super simple. When we make a GET request to get the title, we’ll send a simple html file. Here’s what it will look like in code: routes/get.js const express = require("express"); const expressRouter = express.Router(); const path = require("path"); const titleController = (req, res) =&gt; { res.sendFile(path.join(__dirname, "../components/GET/title.html")); }; expressRouter.use("/title", titleController); module.exports = expressRouter; In the html file we will just have a span with the text Gallery App and that’s it. In principle, it would be possible to make a POST request and add multilingualism to the application, but this, again, is a load on the application. I wanted to make it more or less simple, but at the same time beautiful and functional. Now, all that remains is to connect all of this into one file and launch our server. To do this, let’s import our files and create an express application: app.js const express = require("express"); const path = require("path"); const bodyParser = require("body-parser"); const cors = require("cors"); const PORT = 8000; const app = express(); const getRoutes = require("./routes/get"); const postRoutes = require("./routes/post"); app.use(express.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cors({ origin: true, credentials: true })); const imagesFolder = path.join(__dirname, "./images"); app.use("/images", express.static(imagesFolder)); app.use(express.static(path.join(__dirname, "src"))); app.get("/", (req, res) =&gt; { res.sendFile(path.join(__dirname, "src/index.html")); }); app.use("/api", getRoutes); app.use("/api", postRoutes); app.listen(PORT, () =&gt; { console.log(`Server is running on http://localhost:${PORT}`); }); Here we set up CORS so that we can send a request from another localhost port, and also load images from a folder. Specifically, we do this here: const imagesFolder = path.join(__dirname, "./images"); app.use("/images", express.static(imagesFolder)); Also, you can specify your PORT for the server, but I specified the default 8000. You also need to configure bodyParser for convenient work with HTML and, in fact, just connect the routes to the api. And now, I think, you can safely use the application! Conclusion The application, even such a seemingly small one, turned out to be quite complex given that the minimum functionality was implemented. But, this is also cool, because there is ground for modifications, high-quality assembly, and simply modern modules. You can implement the backend in PHP or something else, the meaning for the client will not change much, so I think that this application can even go well as a pet project. Thank you all very much for reading the article! It turned out to be quite large, even in the case that I tried to shorten the narrative somewhere, somewhere not to cover the subtleties, but even so it turned out to be a lot, but, I hope, interesting and useful for you!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to share components between sites</title><link href="https://blog.hmpl-lang.dev/2024/12/07/how-to-share-components-between-sites/" rel="alternate" type="text/html" title="How to share components between sites" /><published>2024-12-07T01:00:00+00:00</published><updated>2024-12-07T01:00:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/12/07/how-to-share-components-between-sites</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="components" /><category term="reusability" /><category term="web-development" /><category term="JavaScript" /><category term="cross-site" /><category term="tutorial" /><summary type="html"><![CDATA[It is not uncommon to encounter such a task when creating a web application, when it is necessary to transfer a component between sites. Usually, these are some kind of general buttons, blocks like footer, header, and the like. Component For example, we can take the button component, which we will transfer between the components. It will look like this: &lt;button class="button"&gt;Click Me&lt;/button&gt; &lt;style&gt; .button { background-color: #4caf50; color: white; border: none; padding: 12px 24px; text-align: center; text-decoration: none; font-size: 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s, transform 0.2s; } .button:hover { background-color: #45a049; } .button:active { transform: scale(0.95); } &lt;/style&gt; The result on the site will be as follows: Now, let’s take two sites for which you need to make the component common. Let it be example1 example2. They can all be hosted on different hosting sites. Let one be deployed from GithHub, and the other from some local hosting. Now, the main question arises - how to share? Several ways of sharing I will describe several methods that are usually used for this. From the most banal to the most practical. Both of these approaches will look something like this. 1. Output to a file and connection by script This method assumes that there will be a function that returns HTML markup. And, this function can be connected via a file remotely. It doesn’t matter where this file will be located. You just need to connect it from there. createButton.js // buttonModule.js (function (global) { // Define the createButton function function createButton() { // Create a &lt;style&gt; element and add styles const style = document.createElement("style"); style.textContent = ` .button { background-color: #4caf50; color: white; border: none; padding: 12px 24px; text-align: center; text-decoration: none; font-size: 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s, transform 0.2s; } .button:hover { background-color: #45a049; } .button:active { transform: scale(0.95); } `; // Create the button element const button = document.createElement("button"); button.className = "button"; button.textContent = "Click Me"; // Return the elements (style and button) return { style, button }; } // Expose the function to the global scope global.buttonModule = { createButton }; })(window); example1/root/index.html, example2/root/index.html &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Button Module&lt;/title&gt; &lt;script src="https://.../buttonModule.js"&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;div id="wrapper"&gt;&lt;/div&gt; &lt;script&gt; // Use the buttonModule const { style, button } = buttonModule.createButton(); const wrapper = document.getElementById("wrapper"); wrapper.append(style); // Attach styles to the document wrapper.append(button); // Add the button to the page &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; Here we connect the module via a site that is not connected to our two sites. It could be the same GitHub. Features (Advantages): Easy to implement with standard &lt;script&gt; tags in HTML without additional setup. Requires no modern tools or configurations like Webpack or Vite. Suitable for small, single-page applications or quick experiments. Minimal setup, enabling faster development. Can be seamlessly integrated into existing projects that already rely on global variables. Drawbacks: If there are many components, there will be a thousand scripts, which makes this method suitable only for a single use. Adds variables or objects to the global scope, increasing the risk of naming conflicts. Difficult to avoid clashes when multiple scripts are used. Makes the project harder to scale or refactor. Scripts depend on the correct order of loading, which must be manually managed. Less maintainable and not aligned with current best practices. 2. Using a third-party library and moving the component to the API For this method, we will use a module such as HMPL. It will allow you to connect components from the server using simple templates based on objects. To begin with, let’s take the component to the server. Create a separate HTML and give it via API request. What will the .html file look like: button.html &lt;button class="button"&gt;Click Me&lt;/button&gt; &lt;style&gt; .button { background-color: #4caf50; color: white; border: none; padding: 12px 24px; text-align: center; text-decoration: none; font-size: 16px; border-radius: 5px; cursor: pointer; transition: background-color 0.3s, transform 0.2s; } .button:hover { background-color: #45a049; } .button:active { transform: scale(0.95); } &lt;/style&gt; After that, we will need to somehow transfer this file to the server. Let the backend be on Node.js. We will use express.js as one of the most popular frameworks for creating API. First, we will set the route by which we will receive our component: buttonController.js const express = require("express"); const expressRouter = express.Router(); const path = require("path"); const buttonController = (req, res) =&gt; { res.sendFile(path.join(__dirname, "../button.html")); }; expressRouter.use("/getButton", buttonController); app.js const express = require("express"); const path = require("path"); const bodyParser = require("body-parser"); const cors = require("cors"); const PORT = 8000; const app = express(); const routes = require("./routes/buttonController"); app.use(bodyParser.urlencoded({ extended: false })); app.use(cors({ origin: true, credentials: true })); app.set(express.static(path.join(__dirname, "src"))); app.use("/api", routes); app.listen(PORT); After this, we will have a route by which we can now easily take the component. On the site we connect HMPL. It can be connected in several ways, let’s consider the main ones: Via script &lt;script src="https://unpkg.com/json5/dist/index.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; Via import import hmpl from "hmpl-js"; We use method 1, since index.html is the default on our sites. &lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt; &lt;title&gt;Button Module&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;script src="https://unpkg.com/json5/dist/index.js"&gt;&lt;/script&gt; &lt;script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"&gt;&lt;/script&gt; &lt;script&gt; const templateFn = hmpl.compile( `&lt;div id="wrapper"&gt;{{#request src="https://.../api/getButton"}}{{/request}}&lt;/div&gt;` ); const btnWrapper = templateFn().response; document.body.append(btnWrapper); &lt;/script&gt; &lt;/body&gt; &lt;/html&gt; Here we do almost the same as in the first method, but the trick is that now you can safely reuse the component. Let’s say you can do it like this: const btnWrapper1 = templateFn().response; const btnWrapper2 = templateFn().response; Also, there is a lot of additional functionality that comes from the module - indicators, request error handling, etc. Since the module is based on fetch, you can effectively customize requests and do much more. Features (Advantages): Reusing components Suitable for both small and large applications with thousands of components A huge amount of functionality aimed specifically at this server-oriented approach to components displayed on the client Flexibility in use Drawbacks: Connecting two script files Creating an additional API This approach kind of implements the SSR approach, but on the client without the key element for it - visibility for robots, but otherwise - it’s a cool method that can make the solution of the problem easier. Conclusion Depending on the situation, you can use either the first approach or the second. In the first one, you have full control over the process, but it is still not suitable when you need to work with several components, since you will have to constantly import files, which is not good. Thank you all for reading! I hope you found this article helpful!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HMPL integration with JSON5</title><link href="https://blog.hmpl-lang.dev/2024/12/05/hmpl-integration-with-json5/" rel="alternate" type="text/html" title="HMPL integration with JSON5" /><published>2024-12-05T01:00:00+00:00</published><updated>2024-12-05T01:00:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/12/05/hmpl-integration-with-json5</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="JSON5" /><category term="JavaScript" /><category term="integration" /><category term="web-development" /><category term="JSON" /><category term="data-format" /><summary type="html"><![CDATA[The new version of HMPL has integration with the JSON5 module, which will qualitatively improve the work several times! In this article, I would like to describe in more detail why this was done and why it is necessary. About JSON5 First of all, it is worth noting the long-standing problem with JSON, which exists in JavaScript, and indeed in almost any other programming language that works with this format. When working with objects, it seems that everything is convenient and practical. JSON is very convenient and why do we need additional packages at all if there is JSON.parse and JSON.stringify, which will be useful in almost all cases of work? But, let’s take this code: const user = { id: 0, name: "Tony", age: 43, hobbies: ["Building anthill"] }; const jsonString = JSON.stringify(user); Now, let’s output to the console what we got: console.log(jsonString); // output - {"id":0,"name":"Tony","age":43,"hobbies":["Building anthill"]} We got a seemingly ordinary string, which can easily be translated back with parsing and everything is cool, only this string takes up “a lot” of space on the disk, and also imagine if you write all this manually, and not in JavaScript through a convenient object? Yes, this is the main problem with this functionality. If we take the same JavaScript object and write it normally in a string, then JSON.Parse will not parse it, giving an error: const userString = `{ id: 0, name: "Tony", age: 43, hobbies: ["Building anthill"], }`; JSON.parse(userString); // Uncaught SyntaxError: Expected property name or '}' in JSON at position 6 (line 2 column 5) // at JSON.parse (&lt;anonymous&gt;) To fix this, we will have to adjust the string to the format. To do this, we will have to manually constantly write double quotes near the object properties. We will always have to not put a comma at the end, not write comments in the string like in JS, etc. We kind of get convenient functionality, but if we consider it as something that we will write manually, then it is simply incredibly inconvenient, because everyone is used to writing a JS object manually, and not JSON. So, the JSON5 module allows you to write strings almost like in JS and not have the problems described above: import JSON5 from "json5"; const userString = `{ id: 0, name: "Tony", age: 43, hobbies: ["Building anthill"], }`; JSON5.parse(userString); /* { id: 0, name: "Tony", age: 43, hobbies: ["Building anthill"], }; */ Even the slogan of the module itself says: “JSON5 – JSON for Humans”. Of course, the problem may seem insignificant at first glance, but only until it becomes a daily issue. It’s okay to correct quotes once, remove a comma, but doing it manually every day is incredibly tedious. Therefore, as one of the modules that solves this problem, it is the best fit for all of this. You can even remember not abstract examples, but specific ones that are used in work. Have you ever configured a configuration file when working with some code assemblers or something else? The same linters, prefixers, module builders, various text editors - all this works, including through JSON. And, usually, such files are filled manually by users. And, now there is a need to parse such moments, for example, here is an example of a config: const config = `{ "useStrict": true, // or false "withComments": false, "indent": "tab", // "two spaces" ... }`; And, such an object also needs to be parsed on the application side. These parameters can be any and in any format, as well as with comments and other jokes. Manually writing such a parser is not cost-effective, and simply unnecessary. About the benefits for HMPL The HMPL module is based on extended HTML markup, to which we pass objects, and at the output we receive a ready component from the server. Let’s take an example of the code: import { compile } from "hmpl-js"; const templateFn = compile( `&lt;div&gt; &lt;form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form"&gt; &lt;div class="form-example"&gt; &lt;label for="login"&gt;Login: &lt;/label&gt; &lt;input type="login" name="login" id="login" required /&gt; &lt;/div&gt; &lt;div class="form-example"&gt; &lt;input type="submit" value="Register!" /&gt; &lt;/div&gt; &lt;/form&gt; &lt;p&gt; { { src: "/api/register", after: "submit:#form", repeat: false, indicators: [ { trigger: "pending", content: "&lt;p&gt;Loading...&lt;/p&gt;" } ] } } &lt;/p&gt; &lt;/div&gt;` ); const initFn = (ctx) =&gt; { const event = ctx.request.event; return { body: new FormData(event.target, event.submitter), credentials: "same-origin" }; }; const obj = templateFn(initFn); const wrapper = document.getElementById("wrapper"); wrapper.appendChild(obj.response); As we can see, for a custom request to the server, you need to write a couple of properties for which it will be easy to manually put quotes in pairs. Specifically, this is the markup: &lt;p&gt; { { src: "/api/register", after: "submit:#form", repeat: false, indicators: [ { trigger: "pending", content: "&lt;p&gt;Loading...&lt;/p&gt;" } ] } } &lt;/p&gt; Before version 2.2.0, the module was based on JSON.parse, so this whole thing was completely inconvenient. The stringify function was introduced, which somehow bypassed this point, but it’s clear that it’s still in separate ones .hmpl files js code will be problematic to write. Here is an example of stringify and a file: const request = hmpl.stringify({ src: "/api/test" }); const templateFn = hmpl.compile(`{${request}}`); mail.hmpl: &lt;div&gt;{{#request src="/api/test"}}{{/request}}&lt;/div&gt; Therefore, I think that integration with JSON5 is the best way to make sites even faster and smaller in size. Now, it’s generally super convenient, because you can just copy an object from JavaScript and paste it into an HTML file.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Asynchronicity: async await support when working with HMPL</title><link href="https://blog.hmpl-lang.dev/2024/11/26/asynchronicity-async-await-support-when-working-with-hmpl/" rel="alternate" type="text/html" title="Asynchronicity: async await support when working with HMPL" /><published>2024-11-26T14:10:00+00:00</published><updated>2024-11-26T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/11/26/asynchronicity-async-await-support-when-working-with-hmpl</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="JavaScript" /><category term="async-await" /><category term="asynchronous" /><category term="Promise" /><category term="web-development" /><category term="tutorial" /><summary type="html"><![CDATA[In this short article I would like to consider working with asynchrony in HMPL. By default, in order to get a response from the server after an unspecified time, you need to specify a callback function in HMPLRequestInit. The key will be get. In the code, it looks like this: const elementObj = templateFn({ get: (prop, value, requestObject) =&gt; { switch (prop) { case "response": if (!requestObject) console.log(requestObject); console.log("Response:"); console.log(value); break; case "status": console.log("Status:"); console.log(value); break; } } }); With this approach, you can easily work with the server, but what if you need to specify async await so that the code is synchronous? For this, there is a little trick that will allow you to do this. We can wrap the entire code in Promise and resolve it when receiving data. How it looks in code: const val = await new Promise((res, rej) =&gt; { templateFn({ get: (prop, value, requestObject) =&gt; { switch (prop) { case "response": if (!value) return; res(value); break; } } }); }); This way we can easily get the right response at the right time. If the request will take more than a few seconds, then in order not to wait for the server’s response, we can make a setTimeout, which will resolve the Promise when we have waited too long: const val = await new Promise((res, rej) =&gt; { setTimeout(() =&gt; res("timeout"), 2000); templateFn({ get: (prop, value, requestObject) =&gt; { switch (prop) { case "response": if (!value) return; res(value); break; } } }); }); Here, whatever resolves faster will work. Moreover, the macro task setTimeout will not wait an hour until the response from the server from the micro task comes, even if we have such a call stack. That is, timeout should work. Links to documentation: https://hmpl-lang.dev/hmpl.html#compile]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Memoization in HMPL</title><link href="https://blog.hmpl-lang.dev/2024/10/03/memoization-in-hmpl/" rel="alternate" type="text/html" title="Memoization in HMPL" /><published>2024-10-03T14:10:00+00:00</published><updated>2024-10-03T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/10/03/memoization-in-hmpl</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="Memoization" /><category term="Performance" /><category term="optimization" /><category term="JavaScript" /><category term="web-development" /><category term="caching" /><summary type="html"><![CDATA[In version 2.1.3, among other things, new functionality was introduced to improve the performance of sites using hmpl.js. Query memoization is one of the most excellent ways to optimize programming. “What is it and how does it work?” - I will try to answer these questions in this article. The concept of memoization Before proceeding to the consideration of a specific functional, let’s first consider this concept in programming in general. Memoization is the preservation of the results of the execution of functions to prevent repeated calculations. This is one of the optimization methods used to increase the speed of execution of computer programs. Before calling the function, it is checked whether the function has been called before: if it was not called, then the function is called, and the result of its execution is saved; if called, the saved result is used. An example of memoization in JavaScript can be the following code: // Before the introduction of mechanization const reverseText = (string) =&gt; { const len = string.length; let reversedText = new Array(); let j = 0; for (let i = len - 1; i &gt;= 0; i--) { reversedText[j] = string[i]; j++; } return reversedText.join(""); }; const a = reverseText("a123"); // The cycle is running const b = reverseText("a123"); // The cycle is running // After the introduction of memoization const memoizeFn = (fn) =&gt; { const cache = {}; return (string) =&gt; { if (string in cache) return cache[string]; return (cache[string] = fn(string)); }; }; const memoizedReverseText = memoizeFn(reverseText); const a = memoizedReverseText("a123"); // The cycle is running const b = memoizedReverseText("a123"); // The cycle does not work We create a wrapper (a higher-order function) over an already existing function that adds some kind of state, designated cache. The cache stores the arguments and, accordingly, the values obtained from the function. By the key, if it is equal to the input argument, it is already possible to get the finished result in the object without turning the string over again. This is the basis on which all optimization is based. It’s trivial, we don’t repeat the code again, but only take the already calculated value. Also, the object was named cache for a reason. The cache is an intermediate buffer with quick access to it, containing information that can be requested with the highest probability. Here you can already recall the memory that is located between the processor and RAM, but this is clearly a slightly different story. In general, memoization is widely used in software, which makes it an excellent way to quickly speed up a particular code execution. But this method has its disadvantages, of course. The main disadvantage, of course, is the extra allocation of memory for storing the results. If a function is executed once, then there is simply no point in memorizing its return values. Memoization in HMPL Since HTML is a template language for displaying the user interface from the server to the client, http requests will need to be memorized. Accordingly, the intended result will be the preservation of HTML markup. Here is an example of how HMPL works: const newDiv = compile( `&lt;div&gt; &lt;button&gt;Get the square root of 256&lt;/button&gt; &lt;div&gt;{{#request src="/api/getTheSquareRootOf256" after="click:button"}}{{/request}}&lt;/div&gt; &lt;/div&gt;` )().response; According to the event listener on the button, it is obvious that a request to the server can be sent any number of times, but the square root of 256 was 16, so it will be, so the request, theoretically, will come the same. So, the problem with previous versions is that a new element was constantly put on each request, even if the response from the request is the same. Specifically to optimize this process, an additional field was introduced, which is called memo. const newDiv = compile( `&lt;div&gt; &lt;button&gt;Get the square root of 256&lt;/button&gt; &lt;div&gt;{{#request src="/api/getTheSquareRootOf256" memo=true after="click:button"}}{{/request}}&lt;/div&gt; &lt;/div&gt;` )().response; It takes the value true or false. It only works for request objects that are theoretically repeatedly sent. A small diagram has been created to visually display the process: Here, too, the concept of a cache appears, which has already been used before. Also, if we take HTTP requests, then additional concepts of fresh and state response, revalidation, etc. are considered. This all comes from the HTTP cache theory. This point is discussed in more detail in the MDN documentation. An analogy can be drawn that memoization in HMPL is logically comparable to the no-cache value of the caching mode. An example of hmpl working without memoization and with it in the DOM: Without memoization: With memoization: During the test, the button to get the user interface from the server was actively pressed. In one case, we constantly replace the div with a new one, although the response from the server comes the same, in the other, we keep the same element, but only if the responses are the same. Memoization for file types with the .hmpl extension Also, memoization will be available not only for one query object, but also for all objects obtained from the compile function with the memo option enabled: const templateFn = hmpl.compile( `{ { "src":"/api/test" } }`, { memo: true, } ); const elementObj1 = templateFn(); const elementObj2 = templateFn(); It will not interfere in any way with other request objects that are triggered only once. Since the hmpl-loader is based on the compile function, an option will soon be added in which it will be possible to enable memoization for all files with the extension .hmpl: module.exports = { module: { rules: [ { test: /\.hmpl$/i, use: [{ loader: "hmpl-loader", options: { memo: true } }], }, ], }, }; Thank you all so much for reading this article! P.S. See more changes included in version 2.1.3.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Differences between HMPL and HTMX</title><link href="https://blog.hmpl-lang.dev/2024/08/10/differences-between-hmpl-and-htmx/" rel="alternate" type="text/html" title="Differences between HMPL and HTMX" /><published>2024-08-10T14:10:00+00:00</published><updated>2024-08-10T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/08/10/differences-between-hmpl-and-htmx</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="HTMX" /><category term="Comparison" /><category term="web-development" /><category term="JavaScript" /><category term="template-language" /><category term="HTML" /><summary type="html"><![CDATA[Hello everyone! In this post I would like to tell you about the differences between the HMPL template language and the HTMX library. This question often arises when first getting to know the language, so I will try to describe the differences as fully as possible. I have highlighted a list of differences that I believe are the most significant: 1: Concepts. The first and probably the most important difference between HTMX and HMPL is the very concept of the two modules. HMPL is a template language that will be supported and developed as such. That is, linters, themes, syntax support (.hmpl extensions) in text editors, programs, and the like. HTMX is a set of tools that expand the capabilities of html using tags, classes, nesting, and the like. 2: Syntax. The second and no less important difference is the syntax. In HMPL, everything is built on objects. In HTML, you kind of “pass” a request object and, at the output, again, you get an HMPLInstance object, which contains nodes, request status, etc.: &lt;div&gt; { { "src": "http://localhost:8000/api/test" } } &lt;/div&gt; In HTMX the basic syntax is tag attributes, as well as nesting of constructions that relate to the request: &lt;button hx-get="/click"&gt; Click Me! &lt;img class="htmx-indicator" src="/spinner.gif" /&gt; &lt;/button&gt; In this case, the nested structure is an img with the “htmx-indicator” class. 3: Working with javascript. The second and probably no less important difference is the process of working with javascript. In HMPL, all work is built only on javascript. There, objects with nodes are created, RequestInit objects are passed to requests, etc. That is, the very concept of the language assumes that the main work will be done there, although you can make a separate file and write the syntax of the language, all the same, its processing will occur manually through js: const templateFn = require("./main.hmpl"); const elementObj = templateFn(); In HTMX, working with javascript fades into the background. Almost all work occurs in the original html, without resorting to js. This is like a basis, because it is convenient when you connect a file and no longer return to js and get work with the server without hassle: &lt;script src="https://unpkg.com/htmx.org"&gt;&lt;/script&gt; &lt;!-- have a button POST a click via AJAX --&gt; &lt;button hx-post="/clicked" hx-swap="outerHTML"&gt;Click Me&lt;/button&gt; But when you need to pass parameters to the server to receive HTML, configure AbortSignal for a request, in general, integrate somehow more tightly with the server, then HMPL is intended for such options, because this is already work with js. 4: Real DOM. Each, so to speak, “component” of HMPL is independent of anything. That is, when creating an HMPLInstance, it contains a separate node or array of nodes that are not connected to other instances and the real DOM in principle. If you specify the after property in an object, it will search only inside the copy of HTML that is specified during compilation: import { compile } from "hmpl-js"; const templateFn = compile( `&lt;div&gt; &lt;button class="getHTML"&gt;Get HTML!&lt;/button&gt; { { "src":"/api/test", "after":"click:.getHTML" } } &lt;/div&gt;` ); const elementObj1 = templateFn(); const elementObj2 = templateFn(); In HTMX, work occurs with the real DOM and with the document in general. That is, let’s say, the hx-target property will search for a target throughout the DOM: &lt;button hx-post="/clicked" hx-trigger="click" hx-target="#parent-div" hx-swap="outerHTML" &gt; Click Me! &lt;/button&gt; 5: Request sending method. In HMPL, the request is sent by default via fetch, which gives support for future functionality. For now, XMLHTTPRequest support has not been made and, most likely, it is unlikely to be. This has its downsides, because old browser versions will not be supported (fetch was introduced relatively recently, I may be mistaken, but it seems to have been in 2015 as a web api). In HTMX, the request is made via XMLHTTPRequest by default, which gives the advantage of supporting old browsers, but also a disadvantage, because fetch has become a new standard, although in general, this does not affect the work, but, again, XMLHTTPRequest was developed in 2000. Here are the main 5 differences, which, in my opinion, are the most significant between HMPL and HTMX. Of course, you can find a bunch of other minor differences or go and joke and say that there is a difference in 3 letters in words or in sites, but this is not serious. Thank you all for reading the post! Sources: HMPL Docs HTMX Docs]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to reduce javascript file size on client?</title><link href="https://blog.hmpl-lang.dev/2024/08/09/how-to-reduce-javascript-file-size-on-client/" rel="alternate" type="text/html" title="How to reduce javascript file size on client?" /><published>2024-08-09T14:10:00+00:00</published><updated>2024-08-09T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/08/09/how-to-reduce-javascript-file-size-on-client</id><author><name>HMPL Team</name></author><category term="blog" /><category term="HMPL" /><category term="JavaScript" /><category term="File-Size" /><category term="optimization" /><category term="performance" /><category term="web-development" /><category term="Vue.js" /><category term="client-side" /><summary type="html"><![CDATA[Hello everyone! In this post I would like to tell you how you can reduce the size of javascript files several times thanks to such a template language as hmpl. The technological approach that appears in the post is not new, but nevertheless is popular enough today to be worth talking about. Reducing the size of the javascript file will allow the pages to load faster on the client. If we take modern SPA, it turns out that the file sizes, even taking into account all the minifications, are still quite large. Of course, once you load a page once, it’s easier to navigate it, but the first load time itself can be from one second to, say, several minutes with a bad internet connection. Few customers will want to wait that long. When using most frameworks and libraries for creating UI, you have to write a lot of boilerplate code. Each symbol takes up memory space. Let’s take a Vue.js clicker: createApp({ setup() { const count = ref(0); return { count, }; }, template: `&lt;div&gt; &lt;button @click="count++"&gt;Click!&lt;/button&gt; &lt;div&gt;Clicks: {{ count }}&lt;/div&gt; &lt;/div&gt;`, }).mount("#app"); A super simple clicker, but even it requires a fair amount of lines of code in js, let alone those cases when the application is more or less large. Even without two commas, there could be a few bytes less This is not only a problem with Vue, but also with other frameworks and libraries that work in a similar way. But, that’s not the only point. There are a huge number of additional modules that go to them, and to them go the same number of additional modules, and so on to “infinity”. In fact, one of the solutions to this problem was proposed long ago and it is trivially simple - it is to prepare the UI on the server and simply load it on the client. Thanks to this, the size of the application files can be significantly reduced. This is exactly the idea used in HMPL. In the example, I will also try to make a clicker, but using hmpl.js. document.querySelector("#app").appendChild( hmpl.compile( `&lt;div&gt; &lt;button&gt;Click!&lt;/button&gt; &lt;div&gt;Clicks: {{#request src="/api/clicks" after="click:button"}}{{/request}}&lt;/div&gt; &lt;/div&gt;` )().response ); As you can see, the UI will be the same, but the file size will be a little smaller. Even if you minify the files and remove all unnecessary spaces from the templates, maybe the files will be on par or something bigger, but this is just an assumption on small examples. If we take large applications, then it is obvious that with this approach there will be much less js. As can be seen from the example, the functionality of calculating and storing the application state can, if desired, be moved to the server. As you can see from the example, the functionality of calculating and storing the application state can, if desired, be moved to the server. It is clear that if there are a huge number of users, this will simply bring the server down, but the fact that the user interface is the same is important. Yes, of course, this method has not only such a disadvantage, but also the reusability of the UI, how to cache the UI so as not to load everything a hundred times and much more. An alternative is important, which, if properly configured, can compete with most modern solutions. Thank you all very much for reading this post! List of materials: HMPL docs Vue docs]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to GET HTML from API and Display In DOM using HMPL.js (fetch)?</title><link href="https://blog.hmpl-lang.dev/2024/07/22/how-to-get-html-from-api-and-display-in-dom-using-hmpljs-fetch/" rel="alternate" type="text/html" title="How to GET HTML from API and Display In DOM using HMPL.js (fetch)?" /><published>2024-07-22T14:10:00+00:00</published><updated>2024-07-22T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/07/22/how-to-get-html-from-api-and-display-in-dom-using-hmpljs-fetch</id><author><name>HMPL Team</name></author><category term="blog" /><category term="tutorial" /><category term="api" /><category term="HMPL" /><category term="JavaScript" /><category term="API" /><category term="fetch" /><category term="DOM" /><category term="HTML" /><category term="tutorial" /><category term="web-development" /><summary type="html"><![CDATA[Learn how to fetch HTML content from APIs and dynamically display it in the DOM using HMPL.js. Complete tutorial with practical examples and code snippets.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to work with .hmpl file extension in javascript?</title><link href="https://blog.hmpl-lang.dev/2024/06/09/how-to-work-with-hmpl-file-extension-in-javascript/" rel="alternate" type="text/html" title="How to work with .hmpl file extension in javascript?" /><published>2024-06-09T14:10:00+00:00</published><updated>2024-06-09T14:10:00+00:00</updated><id>https://blog.hmpl-lang.dev/2024/06/09/how-to-work-with-hmpl-file-extension-in-javascript</id><author><name>HMPL Team</name></author><category term="blog" /><category term="tutorial" /><category term="HMPL" /><category term="JavaScript" /><category term="webpack" /><category term="hmpl-loader" /><category term="file-extension" /><category term="configuration" /><summary type="html"><![CDATA[Learn how to configure webpack and hmpl-loader to work with .hmpl file extensions in your JavaScript projects. Complete setup guide with examples.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.hmpl-lang.dev/favicon.ico" /><media:content medium="image" url="https://blog.hmpl-lang.dev/favicon.ico" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>