This is wrong because you’re not considering the whole picture:
- to turn the JSON into HTML, you not only need the template you mentioned, you also need code to execute that template (potentially lots of it); preact is 10KB ungzipped (other frameworks, like React/Angular/Ember, are way larger), so your HTML solution is already 10,000 characters ahead (by comparison, the markup you demoed is ~90 bytes per book, so you’re ahead until at least ~100 books on the page, without considering the framework, your code, and the following points)
- HTML compresses amazingly well because it’s repetitive so the overhead is less than you think
- HTML stream renders, so you can start rendering the first book immediately; JSON streaming is technically possible, but not built-in, and quite difficult to implement (and it requires even more JS)
- the same KB of JS is way more expensive than it would be as HTML (or images) because parsing, compiling, and executing is slow
- latency is often a larger problem than bandwidth, especially on mobile, so saving bandwidth is less important than (a) streaming and (b) client-side blocking time
- a large number of users visit one page and bounce, for typical websites, so the promised savings once the SPA is live doesn’t materialize
- the naive way to implement a SPA is _full_ of footguns; first of all, you’d naively load the template for all the pages, making the overhead problem even worse, naively you wouldn’t render anything until the JS has arrived, delaying the TTFMP enormously, naively you’d mess up routing, etc.
- it’s relatively trivial to preload/precache HTML pages, including in a service worker to support offline, making performance on par or better than a SPA
I happily work on a huge SPA daily, for context.