This is one of the (many) reasons why I've started using Phoenix LiveView for all the projects, when I can, that need either partial or full client-side functionality.
By simply keeping all the state, logic, and rendering on the server, all sorts of issues are avoided and various optimizations are possible, and I get full server-side rendering for free!
The client-side, meanwhile, via websockets, only sends events to the server and diffs whatever chunks of markup are sent back. Most of this is via server-side provided attributes (phx-click, phx-change, etc.), but for the slightly more 'exotic' stuff I can add my own events.
Obviously there are cases where this solution isn't practical, but this hasn't been the case for the vast majority of my projects.
By simply keeping all the state, logic, and rendering on the server, all sorts of issues are avoided and various optimizations are possible, and I get full server-side rendering for free!
The client-side, meanwhile, via websockets, only sends events to the server and diffs whatever chunks of markup are sent back. Most of this is via server-side provided attributes (phx-click, phx-change, etc.), but for the slightly more 'exotic' stuff I can add my own events.
Obviously there are cases where this solution isn't practical, but this hasn't been the case for the vast majority of my projects.