If Not SPAs, What?
The Phoenix LiveView pattern is one that I thought was the near-ideal interactive page architecture 20 years ago, long before Elixir and even before XHR was standardised.  (We had other methods for AJAX and server-sent events to achieve it in those days.)<p>It surprises me that there are so few implementations using this pattern today.<p>The Meteor pattern is another good one for the user, if you like things better optimised for user-visible latency (as user interactions happen at the client first), but it hasn&#x27;t ended up with much mindshare now.  Perhaps because it&#x27;s more complicated to use, and perhaps because JavaScript isn&#x27;t ideal for this.<p>Svelte&#x27;s precompiled diffs and minimal client-side code is another pattern I like.<p>For an application I worked on, I developed a combination of those three patterns.  It had a nice and very efficient combination of server-side rendering and client-side immediate interaction, without needing custom JavaScript.  This made it fast, user-friendly and pleasant to develop in.<p>Like LiveView, the client would send user events to the server, which would update affected component model state (which could be shared among different clients too).  Server would re-render any visual components which used the model data (using automatic dependency tracking from previous renders), and then send an async event to each affected client containing an efficient diff of all rendered changes.  If there was much network latency or too much queued, multiple updates would be batched together, merging their diffs efficiently.  The result was the update could be worst-case the size of a page replacement for any number of updates, and at best the size of a few DOM edits in place.<p>But, a little bit like Meteor (but without custom JS), the server could also push &quot;client event-handling hints&quot; in the rendered model to the client.  If an event pattern-matched one of these hints, the update could be applied immediately on the client as well as the event sent to the server.  The server knew what update would have been applied, and could account for it in the diff.  So if the server&#x27;s new rendering matched the client&#x27;s immediate rendering, the diff was empty and didn&#x27;t need to be sent!  But if the server got a different result, for example the event caused an operation which failed, the diff caused the client to receive an appropriate correction.<p>The diffs were calculated efficiently too, not by rendering components and  comparing trees, but by precalculating diff trails from state change patterns where those could be recognised.  For example when one model value changed, if the diff would always be just a string change in the DOM, it already knew and emitted that diff directly.  This meant diff calculation time was as fast as possible in simple cases (event to output in O(1)), and reduced to a reasonable diff time in the most complex cases (such as merged diffs).<p>Keeping it always perfectly in sync and always efficient, throughout network outages, reordered requests, lost events etc was quite technical, but it wasn&#x27;t application specific.  Only the framework needed to deal with the technicality.<p>This was lovely, because it always stayed in sync, it was always efficient for any combination of initial loads, reloads, and sync events, both on slow and fast networks, it worked without JavaScript if needed, had client-side immediate updates for simple logic of a general-purpose nature specified by the server-side, could share model state among different clients and pages, and still didn&#x27;t need any custom JavaScript for the application.<p>As the server side was written in async coroutines and Perl, it didn&#x27;t seem worth the effort of packaging and publishing that implementation as Perl&#x27;s popularity declined (and indeed coroutines seem disfavoured there as well, even though they work brilliantly).<p>I still think that&#x27;s a lovely interactive webpage model, possibly the best.  Nicer than client-side SPAs and nicer than server-side rendering.  It&#x27;s pleasant to develop for, pleasant as a user as well, very fast in many different scenarios including poor network connectivity, and great for sharing live state that appears in multiple pages or documents.<p>I&#x27;d like to implement that again in a modern language, but I haven&#x27;t had any compelling reason to work on a webapp lately.