Htmx - Back to the Server Side
By Chris Gilbert
Warning: This post may contain opinions.
I’ve recently got interested in some of the new developments in web development, and in particular, the htmx library. This is a library that allows you to add dynamic behaviour to your web pages, without having to write any Javascript. It feels to the spirit of the web I knew and loved back in the 90s, which was all about hypermedia, and the ability to link between documents.
I have tried several times to embrace and learn modern javascript frameworks, but I have always found them to be too complex for simple personal projects. As a backend guy, mostly working on DevOps in my day-to-day job, investing the time needed to learn React or Vue.js has always felt like a step too far. I’ve made some progress in learning Angular, since it’s what we use for most frontend development at work, but although I enjoy many of the design choices around encapsulation and using Typescript, I still find the idea of single-page-apps (SPAs) to be a bit of a subversion of how the web was originally conceived.
If you’d like an introduction to htmx, and the ideas behind it, I’d recommend watching this video interview recently with Carson Gross, the creator of htmx.
Where did single-page-apps come from?
In my imperfect memory, but perhaps in the internet’s collective memory too, SPAs (Single Page Applications) came about as a way of making web apps more responsive and interactive. HTML and CSS standards stagnated for a long time, and UI design was becoming more responsive and complex. The web was not keeping up with the demands of the modern user experience.
So, the idea of a SPA was born, where the browser would load a single page with one HTTP request, and then javascript would take over, and dynamically load content as needed. This was facilitated by the XMLHttpRequest object, which allowed the browser to make HTTP requests, and then process the response asynchronously, without having to reload the whole page. First this approach was known as AJAX (Asynchronous Javascript and XML), and resulted in all the Web 2.0 hype (which was largely about UI interactivity), and the ability to make web apps feel more like native apps.
This was a great idea, and it worked around the browser limitations well. But it also had some downsides.
The first is that it’s a bit of a hack. When this train first left the station REST APIs were first designed to send
Hypermedia (HTML) to the client, and the client would then render this to HTML without having to know much
about the underlying data structures on the server side. It’s called the HyperText Transfer Protocol (HTTP) after all,
and at that point, most mature apps were mostly server-side rendered HTML.
Some concepts such as HATEOAS (Hypermedia as the Engine of Application State) have largely been forgotten now, but were arguably an important part of the original RESTful API concept.
As SPAs became more and more popular, eventually the RESTful APIs became more and more like RPC (Remote Procedure Call) APIs, where the client would request or update data, get a response in the form of a JSON object, and then template it into HTML on the client side. This is at the point now where REST in common parlance, now just means an API that uses HTTP verbs to return JSON responses.
The actual Hypermedia part of REST has been largely forgotten.
Then came GraphQL…
This reliance on highly structured data APIs then later caused problems with the result of tight coupling of the client and server. Frontend developers constantly needed to get new endpoints created to avoid over-fetching or under-fetching data, and any data structure change would likely need backend and frontend changes. Given that backend and frontend development have become more specialised (in large part because of the huge increase in complexity on the frontend), this caused the usual communication problems between teams, and the inefficiency that results from that.
GraphQL was created to solve some of this coupling problem, by allowing the client to request exactly the data it needed, and no more. This was a great idea, and it’s been very successful. However, it’s also resulted in a lot of complexity on the backend, and a lot of boilerplate code to create the GraphQL schemas. It’s also arguably solving the wrong problem, as a local optimisation for a systemic issue with the way we build web apps. Would anyone have created GraphQL if we hadn’t already created SPAs? Clearly SQL is a much more powerful and well specified language already available on the server side.
Back to client-server
All of these seem like reasonable engineering design choices for what has largely become a client-server architecture, but it’s not really fitting with the original design intent of HTML as a Hypermedia. It’s also created a highly fragmented web which relies on a lot of custom javascript to function. It’s damaged accessibility, created lots of cargo cult programming, and made the web a less open place.
Today we are in a place where most of the internet consists of 5 websites, each hosting screenshots of the 4. It’s almost impossible to take your data with you, and move it between services. Mobile apps come from walled gardens known as app stores, where you have to pay a tax to the gatekeepers to distribute your software. This is not what the web was supposed to be!
OK, arguably not all of this is the fault of SPAs, but they have certainly contributed to the problem. I mean, who was it that created React in the first place? The archduke of platform lock-in themselves, Meta/Facebook. Who created GraphQL? Again, Meta, to solve problems that they had arguably created for themselves. Whilst these technologies are open source, and useful for many other companies and organisations, are they really a good fit for every use case?
What is htmx?
HTMX is a pretty simple javascript library that allows you to add dynamic behaviour to your web pages, without having to write any javascript. It extends the HTML standard with some new attributes, which you can use to add dynamic behaviour to elements, such as loading content from a server, or updating the page with new content. This concept is known as hypermedia, and it’s what the web was originally designed for.
It’s friendly to existing HTML and CSS developers, and it’s easy to get started with. It’s also very lightweight, and doesn’t require gigabytes of node modules, or a degree in frontend development to understand. That makes it quite appealing to backend folks like me, and those who still want to be able to build web apps without having to learn arcane javascript frameworks.
Where you do want/need to use javascript, it makes hooking into events easy, and it’s also easy to add extensions to extend this behaviour further.
What other complementary technologies are there?
The developer of htmx has written a language called hyperscript which is a less verbose way of adding client side interaction than JS. I am somewhat more skeptical of this (anyone remember CoffeeScript?) but it’s an interesting idea.
I also really like some of the ideas by developers in the htmx ecosystem. For example, here are a few that either complement or seek to so similar things as to htmx:
- Alpine.js - Complementary client framework
- HotWire - An alternative approach to hypermedia
- Hyperview - A way of using hypermedia to build mobile apps
Complementary CSS frameworks
Most people have now heard of Tailwind CSS, which calls itself a utility-first CSS framework. It’s got pros and cons, but it’s not what I would describe as simple, and leads to very verbose HTML. I liked it at first glance, but once I started trying to use it, I found it quite ugly and difficult to reuse styles.
Some things have been built on top of it - and I like the look of DaisyUI for example, which has a lot of pretty and useful components.
However, my needs are simple - I much prefer the approach in CSS Scope Inline which helps encapsulate styles and inherit them in quite a simple way, and perhaps I will try that coupled with Facet, mentioned below.
What about WebComponents?
Web components were meant to help with reuse of components, and to allow you to create your own HTML elements in a standard compliant way that is framework-agnostic. However, they require JS to implement them, and are quite verbose and ugly out of the box.
I recently spotted Facet, which I think would make web components easier, and fits quite nicely in the htmx ecosystem.
But just learn Angular/React/Preact/Next/Nuxt/Vue/Svelte/Apollo/Ember/ad/nauseum!
Yeah, I think you see the problem there just from the title. There are so many frameworks, and their popularity changes on a weekly basis. Even a dedicated follower of fashion would struggle to keep up. I’m looking for something that will serve me for a long time, not until the next big thing comes along in 6 months. This hype-driven-development to cargo-cult cycle doesn’t work for me, and it arguably isn’t sustainable for many other devs either.
Modern client side development is hugely inefficient
I don’t mean from a developer productivity point-of-view - perhaps it’s much more productive to use a modern framework than writing HTML and CSS by hand, or the backend alternatives. Perhaps JSX is miles better than server side view templating, and I just don’t know it yet. But I’m skeptical.
From a macro point of view however, it’s a disaster. The web is now slow, bloated and inefficient. It’s not uncommon to see a 10MB page load, and that’s just for a simple blog post. This is all OK-ish for users with modern hardware, in the previous era of Moore’s Law. But it’s not OK for users with cheaper hardware in the developing world, and it is slowing down everyone, and requiring many more hardware upgrades than would otherwise be needed.
But server-side rendering is solving all these problems!
Offloading client rendering to the server in Next.js or React’s approach, or Vue’s is something that developers have been doing since the start of the web. It’s not a new approach or problem, but it seems to have become in-vogue again, and I think that’s more evidence that there are indeed problems with too much client-side javascript.
Rather than trying to adopt some old server side approaches, some developers have taken the time-honoured tradition of reinventing the wheel, and writing new ways to execute javascript on the server side. This has been accelerated by the fact that javascript is now also executing on the edge in CDNs, and so there is an appealing proposition to use the same language on the client, server and edge. Javascript everywhere, and for everything.
The current problem has really come from the place that we are now - in that client side apps are just too heavy on the client. They’ve become too complex, too slow and bloated, and have polluted what used to be a hypermedia client (the browser) with a lot of what could be considered implementation detail. All the nice abstractions we have in frameworks are not cost free - they require processing, and in the case of client-side javascript, much processing on page load. They also have overhead in terms of complexity, and developer cognitive load.
I’m not sure new infrastructure really helps with that. Arguably CDNs were a solution for too much client side code in the first place - even a web page on the other side of the world is not going to be that slow if it’s just HTML and CSS.
Fin
I hope you’ve enjoyed this post or found it thought-provoking. I am still thinking it thorough and busy on my “learn website development again” journey, but I think a number of moves are making me a bit more optimistic about the javascript fatigue problem, and the web in general. I feel like options are opening up, other than drowning in the javascript ecosystem, or giving up on web development altogether.