← All posts

You probably do not need a framework for this

Not an argument against tools. An argument for checking whether the problem you have is the problem the tool solves.

·2 months ago ·3 min read ·594 words

Every few months someone rebuilds a brochure site as a single-page application, ships four hundred kilobytes of JavaScript to render nine hundred words of text, and then spends a fortnight adding a server-rendering layer to undo the damage. This is not a failure of the framework. It is a failure to ask what the page is for.

Frameworks solve a real and specific problem: keeping a complicated, stateful interface in sync with data that keeps changing underneath it. If you are building a spreadsheet, a mail client, a design tool, a live dashboard — anything where the user's actions continuously reshape the screen — then hand-rolling that synchronisation is a bad idea and you should not do it. The abstraction earns its weight several times over.

The trouble is that most of the web is not that. Most of the web is documents. Articles, product pages, documentation, changelogs, pricing tables, forms with six fields. For a document, the framework's central value proposition — efficient re-rendering of a mutable view — is a careful answer to a question nobody asked.

What you pay by default

The cost is not only the bundle, though the bundle is real. It is the whole shape of the thing:

  • A build step. Now the site cannot be edited, only compiled. Six months later the toolchain has moved and a one-line copy change costs an afternoon of dependency archaeology.
  • Hydration. The server renders the markup, the client downloads a second copy as data, and then walks the tree attaching behaviour to content that was already on screen and already correct.
  • A dependency tree you did not read. Every one of those packages is a supply chain, a licence and an upgrade you will eventually be forced into.
  • A worse failure mode. When a stylesheet fails on a server-rendered page you get ugly text. When the bundle fails on a client-rendered page you get nothing at all.

What the boring version looks like

A data structure, a loop, and markup. On this site the post list is literally this:

<?php foreach ($posts as $post): ?>
  <article class="card">
    <h2><a href="<?= fb_post_url($post) ?>"><?= fb_e($post['title']) ?></a></h2>
    <p><?= fb_e($post['dek']) ?></p>
  </article>
<?php endforeach; ?>

There is no state to reconcile because the page is generated once and then it is finished. Links navigate. The back button works because it is the browser's back button. Text is selectable, findable with the browser's own find, and readable by a screen reader, because it is text in a document rather than a component tree that happens to produce text.

None of this forbids JavaScript. It changes its job. Enhancement, added where it earns its place: a filter that avoids a page load, a form that validates before submitting, a menu that remembers it was open. Each of those is a handful of lines against markup that already worked.

The honest test

Before reaching for a framework, ask three questions and answer them out loud.

Does the interface hold state that outlives a single request? Would a full page load between interactions be genuinely unacceptable, or merely unfashionable? And is the team's difficulty actually rendering, or is it that the data model is a mess and rendering is where the mess becomes visible?

If the answer to "what breaks when the JavaScript fails" is "everything", that is an architecture you chose, not one you inherited.

Sometimes all three answers point at a framework, and then you should use one without guilt. Often they do not, and the honest build is a folder of files that a browser can read.

Related reading