Moving this website from React to Preact

Posted on
Cover image for Moving this website from React to Preact

In 2016, React picked up popularity in Berlin. Despite my weariness about learning yet another framework, I jumped in to stay employable. Now, 4 years in, I write React for a living out of its sheer popularity. The holy wars between libraries, frameworks, or standards never interested me at all. I’ll code with whatever is the best tool for the job, and that’s that.

One of the downsides of this turn of events is that React seems to have created an ecosystem that isn’t particularly healthy. It’s meant to be just a view library, which should make it composable with other bits of tooling, but instead generates a cargo cult of patterns I’d label “toxic”. Ever plowing ahead, the library has added functionality that seems to catter to Facebook and Facebook-scale companies.

Time after time, I arrive at a codebase only to see:

  • business logic scattered across the application
  • at least 6 or 7 indentation levels of providers
  • components wrapped in other bits of tooling that make them hard to test
  • a state management library thrown in regardless of being necessary or not
  • testing done via endless supporting libraries to mock everything
  • client-side payloads the size of a small country
  • components with an expansive hook footprint
  • attempts at DRY that are not domain-bound, but rather brain-dead need for code reuse1
  • a lack of good architectural patterns, some of which have been around for decades

That list could go on, by the way. I also don’t profess to be an expert on anything, so you can take all of that with a grain of salt. That said, it’s not uncommon to have backend developers take a glance at frontend PRs, and then question things they take for granted in terms of patterns and architecture. I plan to write extensively about these small things that make me think the frontend community is lacking some aspects of the professionalism associated with software engineering.

Rediscovering Preact

In the meantime, I thought it might be interesting to have a simple swap between React and Preact. While the latter preaches its smaller size and being closer to the DOM, I’m far more interested in abandoning a tool mainly developer by a company with awful morals. Community-driven efforts should be, all things being equal, our preferred option for developing the open web. That’s my main motivation for using Preact in my side-projects from now on, although the size/performance argument does have its weight.

Evidently, simply moving to Preact does nothing to change the issues I listed above, but it feels like the first step towards redefining what frontend architecture could be. Besides, if two similar tools offer a similar developer experience and functionality, but one is smaller, faster, and maintained by the community, why not give it a go?

Taking the codebase of this website, filipecatraia.com, I decided to give it a go. It’s been a year or so since I last gave Preact a try, but it all went quite well now. My website is built with Next, exported and deployed via Netlify (or Zeit/Vercel, until recently). Moving to Preact was as easy as changing my package.json dependencies. Instead of the usual defaults, I now have:

{   
    ...
    "preact": "^10.2.1",
    "preact-render-to-string": "^5.1.4",
    "react": "github:preact-compat/react#1.0.0",
    "react-dom": "github:preact-compat/react-dom#1.0.0",
    ...
}

After re-building and testing everything, I now have a website powered by Next and Preact, for a reasonable performance boost and faster build times. It Just Works™. To test the speed/performance argument, I decided to run some simple benchmarks, which you’ll find in the table below.

(Please note that timings and sizes are averaged over 20 samples.)

Step Preact React Δ Unit
Build, no cache 20.158 24.612 4.454 s
Build, with cache 17.321 19.281 1.96 s
Size of .next/ 4220.361 5791.045 1570.684 kB
First load JS, / 57.7 90 32.3 kB
First load JS, shared 25.5 57.8 32.3 kB
Export, size of out/ 123.040 123.424 0.384 MB
Finish event, / 230 270 40 ms
DOMContentLoaded, / 108 121 13 ms
Request count, / 44 44 0 N/A
Resource size, / 370 476 106 kB
Total network size, / 614 720 106 kB
Finish event, article page 208 245 37 ms
DOMContentLoaded, article page 95 112 17 ms
Request count, article page 24 24 0 N/A
Resource size, article page 269 374 105 kB
Total network size, article page 537 642 105 kB

These are, by no means, dramatic differences. A 40 miliseconds reduction in load times might not warrant a migration to Preact, but that wasn’t necessarily the point. The reduction in payload is more substantial, and it yields better timings and less data usage for your visitors. If your traffic is predominantly mobile or devices with lesser specs (hint: it probably is), these differences stop being trivial. Also, note that these are the numbers for this particular website, with its meager resource count and sparse amounts of JavaScript.

To gather more information, I decided to test migrating to Preact in an old application. This was a code challenge for a company, an SPA written in React to display birthday records. It’s a fairly simple one-pager, but the results become more impressive: a 53% reduction on network size, and a 2/3 cut in TTI.

I would also argue that cutting 5–10 seconds in build time helps make the case for moving to Preact. In my specific case, I deploy a lot of code to Zeit and Netlify, both of which take build time into account when it comes to pricing. In essence, you’re making your website/application faster for your users, end up with smaller payloads, and build code in less time (thus saving money). What’s not to like?


  1. I heartily recommend reading This Is Not The DRY You Are Looking For
Filipe CatraiaWritten by