tech / Story

The Client-Side Rendering Trap

Why sending 5MB of JavaScript to a phone on a 3G network is a crime. A technical autopsy of , latency, and the hardware reality gap.

2026-02-08
#performance#react#rendering#hydration

The Manifesto: Ofo's Warning

Name: Ofo. Title: The Unfair.

I saw your Lighthouse score. Red. 24/100. A crime scene. You blamed the network. You blamed the "finicky" Google algorithm. You blamed the ads.

I blame you.

You fell into the Client-Side Rendering (CSR) Trap. You believe because you can do everything in the browser, you should.

You are wrong. Your users pay for your mistake.

The Great Disconnect: M3 Max vs Moto G7

The Problem: You live in a fantasy world.

You develop on a MacBook Pro M3 Max. 64GB RAM. Gigabit fiber. Localhost 0ms latency. Your 5MB bundle parses in 150ms. Instant.

The User:
Sitting on a danfo bus in traffic. Motorola G7 Power (2019). Cracked screen. 14% battery. Congested 3G.

On that phone, your 5MB bundle parses in 4 seconds.

4 seconds of locked main thread. 4 seconds of heat. 4 seconds of the user tapping "Buy Now" and nothing happens.

Rage clicks. Curses. Closed tab. Lost sale.

The Three Taxes of JavaScript

Why is CSR expensive? . The mechanics of the trap are governed by the Three Taxes of JavaScript.

1. The Download Tax (Bandwidth)

HTML is text. Small. Streams. First Paint depends on it. JavaScript is a binary blob. Must download completely before use.

500KB Gzipped bundle? 2MB of code. On Slow 3G (400Kbps), that takes 10 seconds. 10 seconds is an eternity. User switches apps. You are forgotten.

2. The Execution Tax (CPU)

Downloading is half the battle. The browser must Parse (Text -> AST), Compile (AST -> Bytecode), and Execute.

M3 Max? Instant. Moto G7 (Snapdragon 632)? 2.8 seconds for 1MB JS. During that time, UI is frozen. No scrolling. No clicking. Browser is chewing React logic.

3. The Tax (The Uncanny Valley)

Modern frameworks (Next.js, Nuxt) send HTML first (), then "hydrate" with JS.

The Visual Lie: User sees the button. It looks ready. But JS isn't loaded. User clicks. Nothing.

The Uncanny Valley of Interactivity:

  1. HTML loads (0.5s). Visuals ready.
  2. JS Download (3s).
  3. (2s).

Total : 5.5s. From 0.5s to 5.5s, your site is a zombie. Looks alive. Is dead.

Memory Leak of Complexity

Let's talk RAM.

(Single Page App) keeps entire state in memory. Every route adds to the DOM Object Structure. Every listener adds to heap.

User browses 10 pages? You hold 200MB. Low-end phone (2GB RAM) kills background processes. Or crashes the tab.

MPA (Multi-Page App) clears memory on navigation. Stateless by default. Robust by design. Stop building memory leaks under the guise of 'App' architecture.

Techniques for the Unfair

Escape the trap. Go back to jQuery? No. Use common sense. Use engineering.

1. Default to Server-Side Rendering ()

Public data? HTML. Pure, boring HTML. Maybe CSS. Need interactivity (like button, form)? Use <form>. Works without JS. Speed comes from Response, not mechanism.

2. Island Architecture (Astro)

Astro defaults to 0KB JS. Treats page as static HTML. Need a pricing calculator? Mark that component as interactive. Astro hydrates only that. Remainder stays static. Respect the hardware.

3. Progressive Enhancement

Build so it works without JS first. Then enhance.

"Add to Cart":

  • Base: Form POSTs to server. Page reloads. Works on every device, everywhere.
  • Enhanced: JS intercepts submit. AJAX request. Updates cart icon. No reload.

JS fails? Base works. You still make money.

The Unfair Verdict

CSR is a tool. Not a religion. Excellent for Applications (Gmail, Figma) with long sessions. Your marketing site is not an Application. Your blog is not an Application. Your e-commerce storefront is a Document.

Stop treating Documents like Applications.

Respect . Respect the device. Respect the user. Send 5MB JS for three paragraphs? You are not a Senior Engineer. You are a vandal. Stop painting graffiti on user bandwidth. Give them the content.