This is a specific example of a class of problems I refer to as "Where the indirection go?" In this case, the indirection is in the form of a function that takes structured data and produces html. That function can execute in the server, or on the client. Which we can term moving a function "closer" or "further" from the client. This is easier to imagine with isomorphic javascript code, but it applies to anything (with an extra translation step as you cross the network boundary).
What you've discovered is a general property of systems that you want to keep your entropy low for as long as possible, and defer the final boost in entropy until the last possible minute. This keeps your options open. It also means publishing low entropy APIs and boosting in the client. In your case, you've correctly noted that it allows you to support different clients more easily.
There are 3 reasons to pay the price to boost entropy on the server: to intentionally make it harder to consume your API, to protect a proprietary boosting function, and because you didn't realize it was bad design.
Interesting way to frame the idea as entropy. Starting every project with a backend and SPA client seems like adding unnecessary entropy.
I'm glad we have middle-way options where we can progressively add dynamic functionality to rich-server, lower entropy applications and make an intentional decision whether to add a rich-client if the need arises.
What you've discovered is a general property of systems that you want to keep your entropy low for as long as possible, and defer the final boost in entropy until the last possible minute. This keeps your options open. It also means publishing low entropy APIs and boosting in the client. In your case, you've correctly noted that it allows you to support different clients more easily.
There are 3 reasons to pay the price to boost entropy on the server: to intentionally make it harder to consume your API, to protect a proprietary boosting function, and because you didn't realize it was bad design.