Is your HTML bloated? A flamegraph can tell you why

I built a HTML Flamegraph tool that help you visualise and diagnose where your HTML payload bytes come from:

HTML Flamegraph

What problems can you diagnose with this?

See some examples below:

  1. You don’t want to block rendering with CSS links. You embed some critical CSS in your HTML. Sometimes this goes unchecked and tens of KBs of CSS goes into your initial HTML that’s not critical at all.
  2. If you carelessly embed SVGs in your HTML it can also increase the size significantly. I’ve seen some pages having low priority footer logos as much as 30% of the initial HTML payload.
  3. You server-side render (SSR) your React app to ensure loading performance is better. But now you have to re-hydrate your SSR-ed markup on the client side using the same state as on the server. 
    This preloaded state goes into your HTML.
Alex Russell’s nemesis

How does it work?

An HTML flamegraph is built from the Abstract Syntax Tree (AST) of your HTML and the AST of any embedded JavaScript code. The y-axis is the AST depth and the x-axis is the uncompressed byte size.

It’s built with the following steps:

  1. Fetch the HTML for the given URL (follows redirects and forwards your User-Agent header)
  2. Parse the HTML into an AST using htmlparser2
  3. Calculate the byte size by subtracting startIndex from the endIndex for each node (please note: this is the non-compressed size!)
  4. Display the resulting tree as a flamegraph using react-flame-graph

When a script tag is encountered we parse that into an AST (using @babel/parser) and merge these trees into one tree.

HTML Flamegraph

I made the tree more readable with useful labels for the nodes where possible:

  1. HTML AST nodes display the first value from their class attribute after the tag name. (e.g. div.carousel)
  2. JS AST AssignmentExpression nodes have the left hand side pretty-printed using @babel/generator (e.g window.__INITIAL_STATE=)
  3. JS AST ObjectProperty nodes have the key pretty printed. This allows nicely inspecting preloaded/initial state for React apps.
  4. and so on…

What are the alternatives?

Lighthouse audits the total size of network requests and also warns about excessive DOM size but doesn’t specifically check your HTML byte size so the problems above can go unnoticed (e.g. a large embedded script on your page won’t increase DOM size).

You can also look at your HTML weight in WebPageTest or Chrome Devtools network waterfalls. I also built a custom Lighthouse audit that shows a byte weight breakdown by resource type.

Alternatives above can show the signs of some problems (if tracked over time) but even then do little to explain why exactly your HTML payload increased. That’s where an HTML Flamegraph helps you out.

Let me know what you think!