BattlefyBlogHistoryOpen menu
Close menuHistory

How many bytes are wasted loading a webapp?

Ronald Chen October 17th 2022

All too often we developers are building websites using powerful computers over fibre Internet. What seems fast enough for us, is dreadfully slow for the vast majority of our users. In the worst case, imagine a person with a 10-year-old phone nowhere near a CDN edge node loading a bloated webapp over 3G. They wouldn't even be able to load the website let alone use it.

We need to aggressively fight against webapp bloat.

The first thing we do, let's kill all the single-page applications

Single-page applications bundle up entire webapps into a single JavaScript file and use the HTML5 History API to fake navigation. This is already wasting bytes for users who don't visit all pages, which is most users. While it is possible to get popular bundlers like Webpack to code split a webapp along pages, the easier way to solve this problem is to use a better bundler like Vite.

Multi-page applications are an improvement

Vite has native support for multi-page applications. Think of each sub-folder as its own independent single-page application. A normal <a href=...> is used to navigate between pages.

This vastly improves the initial load of any page as the Javascript bundle only contains code for a single page. But now we are wasting bytes when navigating between pages. We have to load another index.html for each page.

We are also wasting bytes with client-side rendering. There is an encoding of the UI in Javascript that needs to be translated to HTML DOM nodes. Most commonly this comes in the form of JSX transpiled to React.createElement and then rendered with react-dom.

We can kill two birds with one stone. We can solve the extra index.html and encoding of UI in Javascript. Just send HTML snippets instead of Javascript+JSON.

PHP to the rescue! JK.

Sending templated HTML snippets from the backend? What are we building this with, Perl CGI scripts? Well actually...

Early web tech in the 1990 and the 2000s is a source of inspiration when trying to save all the bytes we can. Back in those days, websites had to load over 56K dial-up modems. Websites were dynamic webpages. Entire HTML pages were generated on the fly with data templated from the database. Javascript wasn't universally available at the time so everything happened on the server. No bytes are wasted encoding the UI in Javascript. No Javascript framework of the month is sent over the wire.

Looks like server-side rendering, but isn't

What does zero bytes wasted look like? Initially, it looks like server-side rendering with all the HTML baked into the index.html. But the tiny Javascript bundle isn't for hydration. This Javascript bundle only listens to interactive components.

For example, let's say we are building a todo app. The initial render is of an empty list.

<html>
  ...
  <body>
    <form id="add-todo">
        <label>
          New todo
          <input type="text" name="new-todo" value="">
        </label>
        <input type="submit" value="Add">
    </form>
    <div id="todo-list">
      <p>All done. Add some more!</p>
    </div>
  </body>
</html>

There is a form to add a new item. When the user clicks on the submits a new todo item, Javascript sends the form to the backend and gets a new todo list in return.

Request

POST /submit-form HTTP/1.1
...
Content-Type: application/x-www-form-urlencoded

id=add-todo&new-todo=delete%20javascript

Response

HTTP/1.1 200 OK
...
Content-Type: text/html; charset=UTF-8

<form id="add-todo">
    <label>
      New todo
      <input type="text" name="new-todo" value="">
    </label>
    <input type="submit" value="Add">
</form>
<div id="todo-list">
  <ul>
    <li>delete javascript</li>
  </ul>
</div>

The server returns HTML snippets with ids which the Javascript simply replaces existing HTML by id. The form is sent back to clear the value and the new todo is added to the list.

Javascript is still required but is minimally used. In fact, this could easily be run 100% server-side if the user is willing to reload all the HTML for every interaction.

This idea of sending HTML snippets to the frontend isn't new, it just hasn't been executed well yet. At its most refined, it would probably look like HATEOAS. For the best-known implementation of this idea, check out htmx, but it's rough at the edges.

This is an extreme idea and likely a bad fit unless one has a tight bandwidth budget.

Do you want to sweat the bytes? You're in luck, Battlefy is hiring.

2022

Powered by
BATTLEFY