Dec 312021

I spent some time playing with Hotwire (for HTML Over The Wire) framework, mostly because it promised building a web application with minimal Javascript. As someone who’s largely a back-end developer and general Javascript non-enthusiast, that fact right there made Hotwire very appealing. Hotwire has absolutely delivered on its minimal Javascrip promise – in fact, I think it’s going to be my first choice for front-end development.

Hotwire is a collection of 3 components. Turbo for linking and updating the page with the server-side-rendered templates. Stimulus is used for the actual Javascript you do have to write, and Strada is described as being to help turn your web application into a mobile application (Strada is set to release in 2021, so it should be out any day now eventually). Overall, using Hotwire’s components is very similar to using Bootcamp, as both rely heavily rely on attributes and properties in your HTML tags.

For my purposes, I was trying to see how much of my simple proof-of-concept I could do completely server-side, and it turns out, the answer was “everything.” I wrote an entire simple demo web application, front end included, and served the whole thing from my back end jar file. Now, while I could write a simple web application that consists entirely of a back end, it’s probably not what I’d actually do. Stimulus is easier to use when you’re building it with proper front end packaging tool. Breaking the front and back ends apart makes for a more logical separation of concerns, and just more readable code. Keeping everything in the back end, and loading Turbo and Stimulus via CDN, and defining your controllers via Javascript module inside your main HTML template is possible, but outside of only having 1 deployable artifact for your front and back ends, there really isn’t any other benefit. If you’re just trying to put together a proof-of-concept that’s going to run locally, or a very small tool that’s either a personal project or has a limited userbase and isn’t critical in any way, then that’s going to be enough. For larger scale projects, you’re likely going to want build and package up your frontend anyways.

Once you embrace the idea of behind server-side rendering, and let the only Javascript you have in your application control interactions with your application instead of logic or rendering content, you’d be amazed at how much you can do on the server. I tried this out by simply re-making a demo utility I had already built using Angular, and Kotlin with Spring Boot, and was able to re-create the whole thing in Hotwire and ktor (I had come across it setting up the version of this same demo, and figured while I was experimenting with a new front end, why not try something new on the back end while I was at it). My “front end” consisted of a couple of Freemarker templates and a CSS file. My backend was a couple of endpoints built to render some pre-defined content in a <turbo-frame></turbo-frame>. It’s pretty similar to the Stimulus demo, except I wanted to pull each “slide” from the backend, as I wanted to ultimately support the option of progressing through the content non-linearly. The only Javascript I needed to keep from the original demo to make the proof-of-concept work the way I wanted was playing/pausing the slideshow and automated progression triggers to my backend call to get whatever “slide” should come next. In fact, the 7.1.0 release enables turbo frames to update the browser history, so I could use the browser history buttons as rewind/fast-forward controls instead of having to write (and maintain) my own (they way I had to in Angular).

Stimulus works well for handling interactions with your web page, even as a module attached to your HTML. I spent a lot of time torn between whether the best approach is to put everything on the back end, and use server-side rendering for everything, attaching the Stimulus controllers as a module in the HTML template I render server-side, or to keep the same approach to front end development we use now, having the base front end separate, with Stimulus controllers, and use server-side rendering for all the places I’d normally use Javascript for content. The former approach is all-in on server-side rendering, and leaves me with a single jar to deploy. However, I haven’t seen a mechanism to unit-test the front-end logic with that project setup. I suppose I could deploy the project as a container and test the running code, but that seems a bit much for a local build or standard branch build pipeline (that level of automated testing is something I’d associate more with regression testing or even a merge into the main branch for a release).

On the other hand, having a dedicated npm project and front end (sans turbo-frame content, of course), does support unit testing, at least based on some preliminary research. Given that’s also how the Stimulus guide assumes your project is set up, I’m also betting that’s the official best practice. I feel a little disappointed at the idea of having to build a separate front end, but that may be just the hype behind the idea that I couldin theory, write something with no true front end at all. Ultimately, ease of unit testing and code cleanliness (and organization) swayed me to not putting everything in a server-side template, although it feels good to know that I could have chosen not to and been fine.

I may still end up making at least part of my existing personal project into something that installs Stimulus and Turbo from CDN and loads controllers as  <script></script> tag modules, because I want to make that part easily downloadable, and I think that’ll likely be the best way to support that (the basic thought here being that on the backend I can just wget an endpoint that would otherwise return the page itself, zip it up, and return the zip file). In general installing Stimulus via npm and deploying a separate front-end project via CDN is probably still the way to go.

As good as Stimulus is (and it’s pretty solid), Hotwire promises that Turbo has the real power, and the more I look at my simple proof-of-concept, the more right I realize that is. It’s not surprising, considering Hotwire is built around taking a server-side rendering approach and that is driven by Turbo. Not only does it remove all the complications that come from trying to implement business logic in Javascript (instead moving it to the backend so all your application logic is in 1 place), but it also allows you to keep state exclusively on the back end, reducing the need to try to figure out working with Redux or Redux-inspired stores for front-end states. It brings us back to the promise of a (mostly) dumb UI. The last time I worked on a dumb UI, I was in college and we still thought building these UIs using Swing was how things should be done, and if you needed a web app you’d just make an applet. In short, Turbo takes a lot of work off the board, mostly by putting it back on my back end where I was trying to keep my logic anyways.

I didn’t play with all of Turbo’s features, but I did spend a decent amount of time with Turbo frames, Hotwire’s approach to partial DOM refreshing. Specifically, using the fact that Turbo navigation integrates with browser history (including, as of version 7.1.0 of Turbo, Turbo frames if you so choose). This would let application users traverse through their activity on the page using the browser’s back and forward buttons, instead of relying on me to keep track of that sort of thing. I didn’t spend a lot of time messing with Turbo streams, but it’s something I can see being very useful for auto-refreshing content.

Hotwire has good documentation, although I’d have to say Stimulus’s was stronger than Turbo’s. I don’t know if that’s because it’s easier to write examples for Javascript controllers vs. a library for navigation and server-side rendering, but there were places in the documentation where I wish there were code snippets (like form submissions redirecting or streaming afterwards, or being slightly more explicit in version 7.0 that updating a Turbo frame doesn’t update the browser history). The only question I couldn’t solve after a little bit of Googling was how to get Turbo frame changes to update browser history (the answer being, wait for the next release). Overall though, the getting started documentation is very good at actually getting you up and running with a real project.

Obviously, don’t re-write your application running in production just because a cool new thing…well…seems cool and new. But it’s absolutely worth at least a research spike, and trying out on new projects. Personally, it’s going to be my first choice of front end when I get to make it, and I’ll likely be advocating for it at work whenever I can. It’s tempting to say that Hotwire is good for smaller front end projects, but after a certain size you’ll need to go back to the bigger frameworks, but to be honest, I don’t see how or where that breakpoint is. Any large-scale front end you can write with React, Vue, or Angular you could write with Hotwire. For people like me, who are primarily back end developers that know enough HTML, CSS, and Javascript to build a front end using existing components, Hotwire is going to keep you in your comfort zone.

1 interesting interaction to bear in mind – I used Apache Freemarker as my templating engine, mostly because I had used in a previous project and it was pretty flexible. Like a lot of HTML templating engines, you designate the pieces you want to replace with data by wrapping it in  ${}. If you’re like me, you do a lot of Javascript debugging (including in your controller) using something like  console.log(`Relevant details that may help me solve my issue: ${myData.myField}`); to log details about your Javascript state. If you included your Stimulus controller as a module in your HTML template, that piece of debugging won’t work (so count that as another good reason to put your Stimulus controllers and basic UI in a dedicated frontend project).

Hotwire is a front end framework that just makes sense, because it’s just HTML, CSS, and as little Javascript as humanly possible. State management is out of the (front-end) picture, and dynamic content on the page is coming to you as HTML, no need to mess with the DOM yourself. If you’re writing a plain old web application and aren’t a full-time front-end developer, Hotwire is a front-end development framework worth trying. I found it kept my logic simpler, my front-end cleaner, and was easier to get the hang of overall – all without feeling like I was missing something that the bigger, better known frameworks would provide. I probably spent more time trying to get back and forward buttons to work with Turbo frame history than anything, and that was before I learned that what I specifically wanted wasn’t implemented in Turbo yet. I’m putting together some demo content for a proof of concept written with a Kotlin backend and Angular front-end, but the next step after that will likely be porting over to Hotwire going forward.

 Posted by at 8:00 AM