Web Dev Ladder
#coding

When building this website I was updating my UI development skills and explored the movement to go back to minimal JavaScript libraries and a different (new?) approach to web pages and web apps in general. I'll go over the project just to set the stage and then talk about some general things I want to highlight.


Project Review and Thoughts

For the very simple main page I used HTMX and a backend Python framework, Litestar. For the admin page, I used Alpine.js for some UI component state and conditional CSS styles. The design itself is done in Tailwind.


Compared to the single page application framework I was using before, Angular, the complexity was reduced quite significantly due to focusing and promoting different things and implementation styles.


The document object model as central artifact was made actually central in describing everything about an HTML page. I did not have to write any additional scripts. Everything was attached to HTML attributes to enhance the behavior of the document: The UI component state, the event triggers and hooks for mutating the document and of course the styles where all there. Anything else logic wise was in the backend, again for parsing and updating parts of the document.


Documents?

The web is documents. I got reminded building this page, that essentially the original thought when building the internet was just to dump information. Only our imagination made documents into apps, and I was reminded of the effort and ingenuity it took to do that building this small addition.

I do have to admit though, that it got crowded and adding layers of attributes might become hard to read and maintain. For this webpage / project size it was manageable, though I had to refactor components several times to separate some behavior into subcomponents. This was mostly done via templating, which forced myself to define interfaces and encapsulation. And of course finding good names, as always the hardest part.


There is also a small issue with the possibilities available to implement a feature. I could use backend logic to replace something, I could build a state in Alpine, or even do some conditional templating. In general this is a plus, but it leads to inconsistent solutions for similar things. I would guess for larger distributed projects guidelines would be necessary. But this is not worse then picking a specific style in single page apps.


I am a bit skeptical if this approach scales to more complex full blown apps. Not just CRUD apps or even just enhanced documents like this page. Especially reactivity, and some declarative pipelines would be hard with the local attribute approach in Alpine on client side only. It probably would work with a backend reactivity approach, where elements on the UI update due to some event.


I actually build something in this direction. A simple approach for chain updates using server sent events, which is supported with an HTMX plugin. Basically in the admin page, a post is uploaded and multiple UI elements are updated with pushed messages containing HTML. I am sure it would be possible to do this also conditionally and with more complex updates or some more abstracted pipeline approach.


Debugging and testing was easy, backend code got regular unit tests and UI was just me clicking through the behavior I wanted to check. HTMX and Alpine made a mature impression and I only had to fix some syntax errors, never having to dive deeply into the libraries.


Developer Experience

In short, I really enjoyed just working with all tools involved. The annoying specificity issues of CSS was nicely solved with Tailwind, and I am fully happy compiling CSS and never touching a class directly again. Working on the document as central object was very straight forward, and getting into the mindset of enhancing HTML tags locally or at most nested one or two levels was easy.


Backend state was the same, as in the end the same object was manipulated. It felt like working on some global state in a sense. You change it, it changes for the user. One thing you work on.


Compared to Angular where you had to maintain a backend and a thick frontend separately with serialization inbetween, this was a big improvement. In my experience, if you provide the ability to implement backend logic on the client side, it will be done. Changing and parsing and understanding the document state gets fractured. I don't mean just the lcoal component state but business logic or validation or anything else. Essentially Angular becomes a general framework or some involuntary backend extension.


In contrast, it is hard to overload the HTML (although possible) with too much state or logic by using Alpine if you do not write any additional JavaScript outside of it. I see this as a benefit and it forces myself to rethink were you actually implement document change. But this might be an issue for more complex pages. I would have to build something larger than this though to really say there is a limit to using the minimalistic approach.


The Ladder

Finally, I can get to the point I wanted to make here. Working with HTML and the minimal JavaScript libraries it felt like starting with the most barebones approach possible. Any complexity was introduced conciously and exactly where I needed it.


It felt natural to refactor in places, when the markdown got too overloaded or the logic had to decouple. In general I would call it something like an architectural flow, similar to a coding flow. Changing how to implement something was mostly effortless, I could think to move something to the backend with HTMX, or do some conditional template if I wanted some different behavior, or use Alpine.js when it was only user presentation concerns.


It was like climbing a ladder in places, first I started with static HTML and was exploring just using that. Then there were some features that needed some backend data, like the posts you see here. So adding HTMX to do that. Next was some disabling of buttons in my admin page, a perfect case for Alpine.js. Every time it got more complex, there was a simple way to fix exaclty the requirement. No need to implement a bunch of abstractions layers or having to find the insert-framework-here way of doing something. It's like having a basic toolset that is versatile enough to create from scratch instead of having a pre-assembled box.


One other thing felt a bit like a ladder. Working so close to the document also highlighted what a browser actually adds to the whole picture. I had a small feature, just copying the URL to the clipboard and it made me aware again that there is a whole API, complete, well thought out and standardized. Usually big UI frameworks wrap this and of course enhances it; but generally I think starting with API first as a junior developer or even when starting a new project is worth it. Even if only for understanding what and why something was wrapped in another framework. Maybe this closes the loop back to why there is resurgence of small JS libraries. Sometimes you have to pick up a screwdriver and a hammer instead of the CNC machine to build something, just to remind yourself of what you actually need.

2024-10-25 v1