Interactive Server-Rendered Webapps: You Don’t Need JavaScript

If you’re a frontend developer who likes to keep up to date with the latest in the JavaScript ecosystem, you’re always in for a wild ride. The ecosystem moves at break-neck speed, sometimes breaking necks along the way. Building a modern JavaScript frontend often involves layers and layers of tooling, increasingly opaque frameworks, and all sorts of configuration and compatibility struggles.

I’m going to let you in on a little secret: you don’t need to write JavaScript to build rich, interactive webapps.  A new generation of frameworks lets you build webapps that look and feel like single page apps (SPAs), but are driven completely by the server–with no JavaScript.  The approach was pioneered by LiveView for the Phoenix framework in Elixir, but is now implemented for a variety of other languages and frameworks as well.  

Lest I come off as a JavaScript hater, I’ll note that I use JavaScript almost every day on projects where it's the right tool, especially those that rely heavily on browser APIs. The point here is not that you should never use JavaScript to build a webapp, just that most webapps do not need the server + client-side app approach.  In this post, we'll look at the interactive server-rendered approach, why it's so powerful, and some of the frameworks that offer this functionality in a number of languages.

How Do Interactive Server-Rendered Webapps Work?

Though the exact details vary a bit by framework, LiveView and similar offerings work just like a normal server-rendered HTML approach, except that they send dynamic updates to the client without reloading the page when the application state changes.

LiveView uses simple declarative HTML rendering based on the current server state. When the client state changes, the HTML template is re-rendered and anything that's changed is sent out to the client in small, compact diffs.  The magic happens behind the scenes with a persistent websocket connection between the client and server.  

There is of course some JavaScript on the client-side which maintains the websocket connection and manages the changes, but it's all built-in to the framework, and doesn't require you, the developer, to write a single line of JavaScript.

Let's take a quick look at an example, take from the LiveView documentation, but simplified for demonstration purposes.  Here we build a simple thermostat component:

defmodule MyAppWeb.ThermostatLive do
  use Phoenix.LiveView
  
  # Set initial view state
  def mount(_params, %{}, socket) do
    {:ok, assign(socket, :temperature, 0)}
  end

  # Respond to "increment" event, update state
  def handle_event("increment", _value, socket = %{assigns: assigns) do
    {:noreply, assign(socket, :temperature, assigns.temperature + 1)}
  end

  # Render the view
  def render(assigns) do
    ~H"""
    <div>
      Current temperature: <%= @temperature %>
      <button phx-click="increment">+</button>
    </div>
    """
  end
end


If you're not familiar with Elixir, the syntax and conventions might be a bit strange, but the gist of it is simple: we have a LiveView with an initial state (called assigns in LiveView), some event handling via handle_event which modifies the state, and a template in our render function.  The special phx-click attribute binds a button click to the backend event.  Once this view is rendered on the client, any time the temperature assign changes, the client is automatically updated with the new HTML.

This simple example shows how basic interactivity is accomplished without a line of JavaScript.  We can easily extrapolate this idea to more complex interactions with additional state, templates and subcomponents.

Interactive Webapps with a Fraction of the Code

Using an interactive server-rendered approach like LiveView is not about avoiding JavaScript just for the sake of avoiding JavaScript: it's about writing far less code than you would build a server and client-app separately.  Let's look at some of the code that you don't have to write with the interactive server-rendered approach:

  • client-side state management
  • server APIs
  • API clients
  • client/server synchronization logic (including polling or socket-based "push")
  • duplicated data models
  • duplicated validation logic

While not every single JS-based frontend requires you to implement every item on this list, these are the kinds of things you need to build and maintain for most single page apps.  Some of these items may be simple, and many can be aided with frameworks or external libraries, but nonetheless, these are by and large the kinds of thing that need to be built and maintained in a traditional client-side single page app.

By taking the interactive, server-rendered approach, you can achieve the same functionality while writing and maintaining far less code.

The Frameworks

The interactive server-rendered approach is available in a variety of different languages and frameworks.  While they do vary in their approach, and may not work exactly the same way as LiveView under the hood, they all implement the same core concept: eliminate the need for a separate JavaScript-based frontend.

LiveView for Elixir

The offering that started it all: LiveView, part of the Phoenix Framework for the Elixir language.  Even beyond LiveView, Phoenix and Elixir offer amazing productivity and a rock-solid high-performance foundation, so if you don't already have another language or framework picked out, I would definitely make Phoenix my first choice.

GitHub - phoenixframework/phoenix_live_view: Rich, real-time user experiences with server-rendered HTML
Rich, real-time user experiences with server-rendered HTML - GitHub - phoenixframework/phoenix_live_view: Rich, real-time user experiences with server-rendered HTML

Blazor for C#

If you're working in the .NET ecosystem, you can get similar functionality from Blazor.  Blazor allows you to write web-app component logic fully in C#.  In addition to the server-rendered approach, Blazor also enables C# based components to run in the client via WebAssembly.

GitHub - dotnet/aspnetcore: ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux. - GitHub - dotnet/aspnetcore: ASP.NET Core is a cross-platform .NET frame...

Vaadin for Java

For Java developers, the Vaadin framework lets you "build your app from UI components without ever having to touch HTML or JavaScript".

GitHub - vaadin/platform: Vaadin platform 10+ is a Java web development platform based on Vaadin web components. If you don’t know to which repository your bug report should be filed, use this and we’ll move it to the right one.
Vaadin platform 10+ is a Java web development platform based on Vaadin web components. If you don&#39;t know to which repository your bug report should be filed, use this and we&#39;ll move it to ...

LiveWire for PHP

If you're using PHP for your backend, you can extend it to cover interactive frontends as well using LiveWire for Laravel.

Quickstart | Livewire
A full-stack framework for Laravel that takes the pain out of building dynamic UIs.

Caldera for JavaScript:

Wait–isn't this whole post about not using JavaScript?  Yes, but it's less about avoiding JS specifically, and more about not building and maintaining a separate client-side app.  If you want to take advantage of the interactive server-rendered approach, but want to use JavaScript on the backend, you can!  Caldera let's you build frontends with server-side executed React.

GitHub - calderajs/caldera-react: Server-side execution for React 🌋
Server-side execution for React 🌋. Contribute to calderajs/caldera-react development by creating an account on GitHub.

Recap

These interactive server-rendered approach is currently the best kept secret in web development. LiveView and similar frameworks let you build webapps with a fraction of the time and effort of a traditional single page app.  In essence, the approach speeds up development by letting you build one app instead of two (frontend and backend), and avoiding the complexity of the JavaScript ecosystem.

If you want to learn more about the approach, or jump into a hands-on example of building an app with LiveView, check out the following!

Why Your Next Web App Frontend Might be The Backend
How LiveView and other real-time server-side rendered HTML technologies are changing how the frontend is written If you’re developing a rich, highly interactive web app in 2022, chances are you’re using some sort of frontend JavaScript framework such as React, Angular or Vue, which talks to a backe…
Build Real-time Chat With Phoenix and LiveView in Fewer Than 50 Lines of Code
If you haven’t experienced the awesome power of LiveView in the Phoenix framework, strap in: we’re going to build a real-time, high-performance chat system with fewer than 50 lines of code. That includes all the code for both the frontend and the backend (spoiler alert: they’re kind