Exploring Hotwire, the new approach to building responsive web applications
Login
Technology

Exploring Hotwire, the new approach to building responsive web applications

If you thought that React was overkill and building the whole UI in javascript was not a good idea, then you've been waiting for Hotwire for a long time.
Building UI with javascript was always a daunting and complex task. Many have tried, few have fully enjoyed the experience. And then, Facebook released React. Google followed with Angular and the world of developers rejoiced. 

All was well. Or so we thought.

Somehow building the whole UI in javascript felt a bit off.  What was the problem with building apps using the modern javascript application frameworks? 

First, there was javascript. The language itself, a relic from the early days of the internet, has been monkey patched over the last two decades to make it semi-usable by programmers.  

Second, there was a design issue. Should the whole app be built using javascript (some form of NodeJS + React combination) or should we build a backend and front end separately (React with PHP or Angular with Go)?  

Finally, there was the question of architecture. Rather than making things simpler, the new frameworks forced developers to resurrect  1990s application architectures.  

Source: IBM



Javascript front end app was in Tier 1 (The presentation), Tier 2 (Business Logic) was your back end Node or Python system, Tier 3 (Data/Resource was your data storage layer.  This setup essentially meant that you were always building two separate applications that needed to communicate with each other using some form of a protocol (i.e. marshaling and un-marshaling JSON). 

This form of architecture offered little in terms of value and increased unnecessarily the complexity of the web applications. And made developer's lives that much harder and stressful. 

Why couldn't we make building web applications simple? A little bit of javascript for some client interaction and the rest, simple HTML sent over the wire to the client. It seemed like a tall order, but I think we are finally on the path to fulfilling it.
 
Enter, HotWire.

It's an HTML over the Wire framework that eliminates the need for building two separate applications and simplifies how we can build our apps. We have started to experiment with it here at TeamHQ and will be releasing a side-project soon, built on HotWire. 

Before we dive into this new framework, let me share a quick story about our own version of the HTML over the wire framework. It should help explain the concept of how HotWire works. 

Our Version of HTML over the Wire


When we started building our app, TeamHQ, we made the decision not to fall into the React/Angular two apps in one trap.  There were a couple of reasons for this. 

First, we had no resources to learn a new framework and the second time was of the essence.  So we built our own reactive app framework in javascript. At only 100 lines of javascript code, 10 lines of ruby, it helped make our application UI more responsive and reactive.  

It works very similarly to how HotWire works.   

The basic premise was that HTML components should be easily update-able without the need to send JSON data back and forth.  This meant that we should be able to define components in our HTML pages.

To solve this problem, we built a simple component tag that had an src attribute. 

<ajax-component id="my_tasks" src="/tasks/1" preload="true">
Loading tasks...
</ajax-component>

On the backend, we had a partial with filename show.component.erb which rendered HTML back to the browser.  Our javascript library would then update the HTML inside the ajax-component tag.

show.component.erb
render "my_tasks_list", tasks: @tasks 

To update components from another action, we built a simple javascript function that would force a component to reload.

Called from other actions, for example, create.js.erb
updateAjaxComponent(component_id, broadcastToAll = true, fireEvent = false) 

This simple solution has worked out well for us.  All the heavy lifting of inserting/replacing/updating HTML is done by our javascript library, all our application has to do is tell it when it should do it and respond with the right HTML template when needed. 

HotWire follows a similar concept, but with a few extra features.  

It includes the component updating/reloading part, but also provides the ability to make non-component pages work seamlessly.  

We will be switching our own implementation to HotWire because it just makes sense and, in the future, it will have a great community behind it, 

But first, we must learn how it works. 

Understanding HotWire


First, what is HotWire?  

It's a cool piece of tech developed by the people who gave us Rails and Basecamp. Here's an official explanation: 

Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire. This makes for fast first-load pages, keeps template rendering on the server, and allows for a simpler, more productive development experience in any programming language, without sacrificing any of the speed or responsiveness associated with a traditional single-page application.

Basically, HotWire helps developers build awesome web applications without losing their hair and wandering off into the forest.  It makes things simpler. Not simplistic, simpler. 

It consists of three supporting frameworks:

  • Turbo: a set of tools that make your pages render seamlessly, without reloading CSS and javascript first loaded in the HEAD section of your HTML pages. 
  • Stimulus: a javascript framework that makes it super easy to manipulate HTML. You write a controller, add a couple of methods that will do something on the page, and wire up the controller to a piece of HTML by adding a data-controller attribute.  It takes care of all the difficult event handling for you and ensures your javascript doesn't leak memory. That's right, there's a way to leak memory with javascript. 
  • Strada: Makes it easy to transfer your HTML skills to the mobile environment.  You can build your web app and then with a few additions, make it work on iOS or Andriod,  (It is coming soon).

Since Strada is not ready yet, We'll only be taking a deeper dive into Turbo and Stimulus.

Turbo-charge your application


Turbo makes your application quicker, more responsive, and easier to develop.  It works by ensuring that subsequent visits to your application's pages aren't loading your javascript and CSS assets all the time. 

Normally, when you click on a link, the browser would fetch the HTML for the new page and then fetch javascript and CSS files, followed by images. By design, this happens on every request.  On small pages, it makes little difference, but for modern web applications, it could become a significant time waster. Some javascript and CSS files can be close to 1 MB in size each. And loading and processing them takes time.

Turbo improves this process by removing the unnecessary fetching and processing of things that don't change. In this case, javascript files and CSS and images. 

When you click on the link, Turbo fetches the new page via an AJAX call, reads through the HTML and takes out the part that's changed, and replaces it on the page you are looking at.  To make the experience seamless, it also replaces the URL you see in the browser, page title, etc.  All of this happens in the background, so you might not even notice any visual processing. It can be extremely quick.

Of course, this is a bit of an oversimplification.

Turbo performs many complex tasks to make life easier for developers and users, but on the whole, its job is to replace the parts of the page that's changed without reloading the whole page. 

To do that is uses four separate mini-libraries.

Turbo Drive - this library does full-page replacements without the need to reload the whole page.  It works for form submissions and links.  You can make your whole application super fast just by using a bit of caching and Turbo Drive.

Turbo Frames - this library is similar to Turbo Drive in that it replaces content on a page without reloading the page. While Turbo Drive replaces the full page content, Turbo Frames allows you to specify which sections of the page should be replaced. 

Not only that, with Turbo Frames, you can also load sections of the page asynchronously, after the page has loaded. This helps tremendously with web application pages that are complex and are required to show a lot of data at once.

Turbo Streams - this library serves two purposes. The first purpose is to deliver the HTML sections to be replaced in Turbo Frames.  When you click on a link that requires a change in Turbo Frame, the response sent will be delivered and processed by Turbo Stream. 

The second purpose is to update other connected browser clients looking at the same content. This makes it easy to make other users see changes you are making in real-time. 

Turbo Native - this library makes it easy to build once and has its work on multiple platforms. For example, Turbo Native makes your HTML-based pages would work properly on iOS and Android devices, without any special tricks on your part.

All you have to do is make sure that your content is mobile-friendly. For special cases, when a different layout is needed, Turbo Native provides an easy method to create screens specifically for mobile devices.

You can read more about Turbo on their official website here

Why Turbo


Why Turbo?  A simple answer is because it offers a simpler method to building modern, progressive, and responsive web applications.  It does that with minimal use of Javascript and leverages your existing application's ability to deliver HTML over the wire to the browser.   

More specifically, it helps you keep most of the business logic where it belongs: on the business end of your application (the backend). It keeps the front end clean and simple.  It reduces your costs by removing the need to hire "front-end" developers. It makes it easier for your designers to design beautiful and effective user interfaces. And it makes upgrading and enhancing applications a much quicker and painless process. 

From the Hotwire Website: 

[Hotwire and Turbo is designed to help you create a] more productive development experience in any programming language, without sacrificing any of the speed or responsiveness associated with a traditional single-page application.

And who doesn't want that? 

What is Stimulus?


In version 2.0 now, Stimulus has been around for a few years and is the child of the same people that created HotWire and Basecamp. 

In its origin, it was probably a reaction to over-bloated front-end javascript frameworks that created their own versions of HTML to help you build components that rendered normal HTML.  Come to think of it, it was likely a reaction to those over-bloated frameworks.

First, a bit of history. 

When the web was in its infancy, HTML was born to help organize the information sent back from the server to the browser.  It had its flaws, and over the years it developed into the de-facto standard for the Internet.  Browsers' only job is to read, process, and display HTML.  

HTML was simple to use and understand. But people wanted interactivity.  So javascript was invented. The origin of that name goes back to the early days of the java programming language and other than a bit of syntax similarity, it bears little resemblance to Java.   

Originally called Mocha, javascript became the de facto standard for browser development. But unlike HTML, which evolved by making itself more of a standard, javascript evolved by making itself into a collection of competing frameworks.  

These frameworks, competing with one another,  developed a myriad of ways of delivering HTML back to the browser, several creating their own versions of HTML. What everyone should have been focusing on instead was making the language itself more standardized.  

Before Stimulus (BS), the front-end development world was becoming too unwieldy and too complex. We needed to get simplicity back.  Enter Stimulus v1.0. 

From their website: 

Stimulus is a JavaScript framework with modest ambitions. It doesn’t seek to take over your entire front-end—in fact, it’s not concerned with rendering HTML at all. Instead, it’s designed to augment your HTML with just enough behavior to make it shine. 

That's right, it's a framework designed to leave your HTML alone.  It's a framework designed so that your developers and designers can work on your application together. It's a framework that defies such terms as "Full Stack Developer" or "Front End Developer".   It's simple enough that even a "Back End Developer" can understand.

How does it work?

Stimulus uses controllers to add behavior to your HTML.  For example, let's say you want to show new notifications for your users when the user clicks on an icon.  First, you must create a controller to handle this behavior.  The controller can be attached to any HTML element, in this case, an icon, via a data-controller attribute (see below). 

Next, in the controller, you can create a method called fetchNotifications that would handle getting the notifications from your back end.  To call that method, all you'd have to do is add data-action="click->notifications#fetchNotifications" attribute to the icon. 

The fetchNotifications method would get notifications from the server and render them how you see fit. With HotWire, it would fetch the HTML with notifications and use TurboStream to display it in the right place. 

Here's the HTML:
<div id="notifications_icon" data-controller="notifications">
  <i class="fa fa-bell" data-action="click->notifications#fetchNotifications"></i>
</div>

Here's the Controller (notifications_controller.js):
import { Controller } from "stimulus"

export default class extends Controller {
  fetchNotifications(event){
    // ... fetch notifications .. 
    // Rails.ajax call or something else
  }
}

Stimulus makes it super simple to attach multiple actions to your elements. If you wanted to load the notifications first and show the notifications after, this is easily done with Stimulus.

To make this work, you could create another function in the controller called show. This function would be responsible for showing your notifications. Make your previous function responsible for loading your notifications. 

Then, in the HTML, you'd just rewrite the data-action attribute to load notifications on mouse hover, and show notifications on mouse click. Like so:

<i class="fa fa-bell" data-action="mouseover->notifications#load click->notifications#show"></i>

The best part about this approach is that now anyone looking at this HTML can tell what it does.  Even your designers can figure out that when someone hovers over the icon it will load notifications and when someone clicks on it, it will show these notifications.

You can make it even more advanced by making the loading part happen only on the first hover.  This type of improvement would make showing notifications almost instantly.

There are many other ways StimulusJS can make your life easier. Since controllers are reusable, you can attach them to any HTML element on your page. 

For example, you can make a Utils controller with functions for showing/hiding elements on hover, performing background AJAX calls on clicks and hiding elements on pressing Esc.  After you've created the controller, you can wire it up to any element on the page.

Stimulus provides developers with great power and a simpler approach to building modern-day applications.

Version 2 of Stimulus has improved its capabilities. It is faster, more stable and a truly powerful javascript framework out there. 

You can learn more about StimulusJS here

Conclusion


Building UI with javascript was a daunting and complex task. Despite many attempts to create more complexity, more unnecessary work, and more stress, the light can be seen at the end of the tunnel now.  

To build interactive, responsive modern-day applications try HotWire and its techniques. You will be truly amazed by its capabilities and what you can accomplish with this new framework. 
 

Sources:
Client-Server Architecture: IBM
What is Hotwire: https://hotwire.dev/
Turbo: https://turbo.hotwire.dev/handbook/introduction

Get Tech and Tips Thursday articles in your email.