This is a distinction between computation that is performed on a server, using arbitrary tools, and computation run on a user's machine locally. The former is much more flexible, but comes at a cost of latency; all user input and output must be serialized, and transmitted a long distance. Front end code can result in much lower latency to the user due to ommitting this transmission.
It makes sense to apply a suitable mix of these two tools that varies based on an application's details. For example, an immediate UI response that can be performed using only information already present on the client makes sense to be handled exclusively there, as computation time is minimal compared to transmission and serializtion.
I believe that JS being able to be used on a server is not relevant to the core distinction.
So it’s not just easy to take code that runs on the server and run it on the client. Anytime the client needs to do more than one round trip, it would have been faster to render the data completely on the server, html included.
Additionally, with SPA’s there’s a lot of nuance around back/forward handling, page transitions, etc. that make a page based application awkward to turn into a purely client side one.
OData batch, GraphQL, and similar technologies exist to reinvent this wheel:
"What if instead of a hundred tiny calls we made one high-level request that returned a composite formatted response that includes everything the client needs to show the next state."
Also known has... server-side rendered HTML like we did since the 1990s.
A lot of the trouble is how that data is "initialized". State management and state ownership are old complications in every client/server application back to the dawn of time. In the old "Progressive Enhancement" days all of the state was owned by the HTML DOM and JS would pick that up and reflect that. In a lot of the modern SPAs the state is owned by the JS code and the DOM updated to reflect it. The DOM never has a full picture of the "state". So state has to be passed in some other channel (often referred to as "hydration" by data/state as water analogy).
Also, in most of the SPA frameworks, state management is deeply entangled with component management and the internals of how everything is built. It may not be deterministic that the server running the same code gets the same data, produces the same results. It may not be easily statically analyzable which components in the system have which data, which outputs given which data are repeatable enough to ship across the wire.
(I just released a low level server-side rendering tool for Butterfloat, and one of the things that kept it easy to build was that Butterfloat was built with an architecture that more clearly separates static DOM from dynamic updating state bindings.)