esc
Anthology / Yagnipedia / The Framework Wars

The Framework Wars

A Field Guide to Every Way Humanity Has Tried to Put Text on a Screen
Meta · First observed 1993 (the first CGI script), though the hostilities intensified around 2013 · Severity: Ongoing — ceasefire not expected

The browser can render HTML. The browser has been able to render HTML since 1993. The browser is, by any reasonable measure, extremely good at rendering HTML. The browser does not need help.

The history of frontend development is the history of helping the browser do something it already knows how to do, and then building frameworks to manage the complexity of the help, and then building meta-frameworks to manage the complexity of the frameworks, and then writing blog posts about how the next framework will make everything simple again, which it will not, because the browser could render HTML the entire time.

This is the field guide to that war. Sixteen articles. Sixteen ways to put text on a screen. One developer’s journey through the wreckage.

“I have been putting text on screens since 1976. I have used one tool. The tool is printf. The text appears. I am told this is no longer sufficient. I am not told why.”
The Lizard, surveying the battlefield from a safe distance

The Delay

These articles were delayed. The machine was slow. Investigation revealed fourteen Electron processes consuming 6.2 GB of RAM — each one a Chromium instance, each one a browser pretending to be a desktop application, each one consuming more memory than the Apollo 11 guidance computer had available. The irony of being unable to write articles about web frameworks because a web framework had consumed all available resources is the kind of recursive problem that this encyclopedia was built to document.

The Electron processes were terminated. The machine recovered. The articles were written. The articles are about the frameworks. The frameworks include Electron. The loop has no base case.

The Eras

Era 0: Before the War (1978)

Before the frameworks, before the browsers, before the wars, there was a terminal. It displayed 80 columns and 24 rows. It had 4 KB of RAM. It was sufficient. Everything since has been a footnote with better fonts.

Subtitle: The Last Time Anyone Got It Right

Era I: The Unification (2006-2012)

The browser wars had fractured the web into four incompatible platforms. Then a dollar sign appeared.

Subtitle: The Dollar Sign That Unified the Web and Never Asked for Credit

Era II: The Frameworks (2010-2016)

Someone decided that the browser needed help rendering HTML. The browser disagreed. The industry did not ask the browser.

Subtitle: The Enterprise Framework That Brought Dependency Injection to the Browser Because the Browser Was Having Too Much Fun

Subtitle: A JavaScript Library for Building User Interfaces and Consuming RAM

Subtitle: The Framework Everyone Recommends and Nobody Is Passionate About

Era III: The Counter-Reformation (2016-2020)

A small number of developers looked at the frameworks and asked: “what if less?”

Subtitle: The Framework That Compiles Itself Out of Existence

Subtitle: The Boring Workhorse That Was Right All Along

Subtitle: Two Lines of Magic, Three Lines of Regret

Era IV: The Meta-Frameworks (2016-present)

The frameworks were not enough. Frameworks needed frameworks.

Subtitle: Zawinski’s Law Made Manifest

Subtitle: The Radical Act of Shipping HTML

Era V: The CSS Wars (2011-present)

A parallel conflict, fought in class attributes, where every framework promises to make CSS easier and delivers a different kind of difficulty.

Subtitle: The Framework That Made Every Website Look the Same, and Everyone Was Grateful

Subtitle: The Framework That Replaced CSS With CSS, but Abbreviated

Subtitle: The Classless Framework That Was Perfect Until the Application Needed a Class

Subtitle: The Component Library That Isn’t a Component Library, Which Is the Point

Era VI.5: The Armistice (2025-present)

After fighting every CSS framework and losing every battle differently, one developer arrived at the conclusion that the PKM article warned about: the best system is the one you don’t notice using.

The lifelog blog has 651 lines of CSS in a Go function. No framework. No build step. No !important declarations. No vocabulary to memorise. Seven storyline themes, responsive layout, dark mode, Wikipedia-style infoboxes — all in css() string, embedded with go:embed, served with the binary.

The V4 product has 13,000 lines across 34 CSS files — its own custom framework, inspired by shadcn/ui’s aesthetics but semantic to the application’s domain. BEM-inspired naming. tokens.css for design tokens. Classes like .pipeline-card and .metric-badge instead of flex items-center justify-between p-4. The class names describe what things are, not what they look like. The CSS knows the product. The product does not know about CSS frameworks.

This is the armistice: stop fighting frameworks. Write CSS. Per project. Per purpose. Let the classes describe the domain, not the layout. The cascade works when there is nothing to cascade against. 651 lines is not elegant. 651 lines is free. The full manifesto — if a practice this simple deserves a manifesto — is in Roll Your Own CSS.

“The developer fought five CSS frameworks and lost to each in a different way. Then the developer wrote CSS. The CSS won because the CSS had no opinions to disagree with. The CSS was the developer’s opinions, written down, in a file, in a function, in a binary. The Lizard has been doing this since 1976. The Lizard calls it printf.”
The Passing AI, on the end of the CSS wars

Era VI: The Desktop Wars (2013-present)

The frameworks escaped the browser and colonised the desktop.

Subtitle: The framework that proved desktop apps could be websites, and websites could consume all available RAM

Subtitle: The framework that proved desktop apps don’t need to ship a browser, then waited patiently for the industry to notice

Subtitle: The framework that is Tauri for Go developers, if you can wait long enough for v3 to ship

The Outsider

Subtitle: The Enterprise Platform That Refused to Be Enterprise

The Pattern

Every framework in this list got something right:

Framework What it got right What it got wrong
jQuery Browser unification, $(), no build step Nothing (the industry got jQuery wrong)
Angular Enterprise structure, TypeScript-first Being Angular
React Component model, ecosystem size Bundle size, hooks complexity, the Virtual DOM
Vue Developer experience, documentation Adoption (everyone recommends, few commit)
Svelte Compiler approach, reactivity The SvelteKit boundary
HTMX HTML is the product, not the artifact Features (by design, and that’s the point)
Hyperscript Readable micro-interactions in _ The third line (and everything after it)
Next.js Full-stack React, SSR Caching, complexity, Vercel coupling
Astro Zero JS by default, islands Awareness (nobody knows about it yet)
Bootstrap Making the web look acceptable Making the web look the same
Tailwind CSS Utility-first, design systems class attributes longer than the content
Pico CSS Semantic HTML, zero config Scaling beyond a prototype
shadcn/ui Copy-paste ownership, design quality The stack tax (React + Tailwind + Radix + TypeScript)
Custom CSS Domain semantics, no opinions to fight Writing it yourself (which is the point)
Electron Cross-platform from one codebase RAM, disk space, the environment
Tauri Native webviews, Rust, 27 MB Awareness (still)
Wails Tauri’s concept in Go Shipping v3

The last column converges: every framework’s weakness is a variation of “the simple thing is hard.” Making it fast is hard. Making it small is hard. Making it ship is hard. Making it stop expanding is hard. The browser could render HTML the entire time.

The Migration Path

This is one developer’s journey through the frontend landscape:

2008              2012              2015              2020
jQuery ──────→ Bootstrap ──────→ React ──────→ Vue (briefly)
                                    │                │
                                    │    2022         │
                                    └──→ HTMX ←──────┘
                                          │
                                          ↓
                                     Go + templ
                                     + HTMX
                                     + Pico CSS
                                          │
                                          ↓
                                    the lifelog
                                    you are reading
Meanwhile, on the desktop:

Electron apps ──→ Electron apps ──→ too many Electron apps
                                          │
                                   Tauri (observed)
                                   Wails (desired)
                                          │
                                   Octarine (27 MB)
                                   NotePlan (native)
                                          │
                                   the machine is
                                    faster now

The endpoint is server-rendered HTML with six HTMX attributes. The Lizard has been at this endpoint since 1993, minus the attributes. The journey was fifteen years and eight frameworks longer than necessary. The journey was also the point, because without it, the developer would not have the specific, hard-earned conviction that the browser can render HTML without help.

The Lizard’s Position

The Lizard does not participate in the framework wars. The Lizard renders HTML with printf. The HTML arrives at the browser complete. The browser displays it. The process has not changed since 1993. The Lizard has not changed since 1976.

The Lizard has been asked to comment on each framework. The Lizard’s responses, compiled:

Framework The Lizard’s response
VT100 “Home.”
jQuery Nod (once, slowly — the highest compliment)
Angular “I am unfamiliar with this technology.”
React “You ship a reconciliation engine to update a <span>?”
Vue “I do not distinguish between these.”
Svelte “Acceptable. It disappears. Things that disappear are honest.”
HTMX “This is what the browser does. You have named it.”
Hyperscript “Two lines: acceptable. Three lines: you are writing prose where you should be writing code.”
Next.js “This is a web server. You have complicated it.”
Astro almost nods
Bootstrap “The web looked the same. This was an improvement.”
Tailwind CSS “These are inline styles. You have renamed them.”
Pico CSS “This is HTML. Styled. Correctly. Why did this require a framework?”
shadcn/ui “You copy someone else’s code into your project and call it ownership.”
Custom CSS “This is what I have been doing since 1976. You have a name for it now.”
Electron “You have put a browser inside an application. The application was already in a browser.”
Tauri “Uses what the OS provides. This is correct.”
Wails “I will comment when it ships.”

Measured Characteristics

“Sixteen ways to put text on a screen. The browser can put text on a screen. The browser has always been able to put text on a screen. The war is between the people who help the browser and the people who replace the browser, and the browser is in both armies, and the browser is fine either way, because the browser just renders HTML.”
The Lizard, who has been rendering HTML since before the browser existed

See Also

Every link above. This is, after all, a Map of Content for a war with no peace treaty. Linking to everything is either comprehensive documentation or an act of provocation, depending on which framework you use.