<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="192066" data-post-id="192066">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="pedromtavares" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/pedromtavares/120/15263_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  pedromtavares
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Would you mind sharing those prototypes? I think they can be a first step to materializing what you’re proposing here. The further we push this discussion forward the higher the probability of someone getting curious enough to elaborate and come out with a proper ‘bridge’ solution.</p>
<p>I completely agree that incremental steps are best so the easier we make it for existing projects to leverage LiveView with more confidence, the better.</p>
<p><a class="mention" href="/u/chrismccord" rel="nofollow">@chrismccord</a> what is your take on this?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192066" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/53">Post #52</a>
	                </div>
	            </div>
              <div id="likers-container-192066" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192066"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #52"></div>
  </section>
</div>
    <div class="postbit" id="192067" data-post-id="192067">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="harmon25" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/120/1274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  harmon25
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Not sure how much is ‘alot’ of JS…</p>
<p>Lots of UI challenges people have with LiveView for example require writing JS.</p>
<p>It’s a bit of a false promise live view eliminates the need to understand and write JS… To some extent it is true, but at which point is it too much?</p>
<p>If all you have are a bunch of mostly stateless React/Vue components, is that alot of JS?</p>
<p>I think what quantifies as a lot of JS is all the code in your front end that isn’t just a stateless view…</p>
<p>Think we both are on the same page that reducing the amount of JS required to make a compelling app is what we are after.</p>
<p>The time I have spent looking at LiveView code it appears to me is highly coupled to the concept of a DOM, and the DOM hierarchy. It’s pretty much a virtual DOM in the BEAM. Not sure how the current implementation could be broken into API vs UI bits. That is the motivation to Redex as it is just a composable state graph/tree. Doesn’t know or care anything about DOM.</p>
<p>EDIT:</p>
<aside class="quote no-group" data-username="bjunc" data-post="52" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjunc/48/16781_2.png" class="avatar"> bjunc:</div>
<blockquote>
<p>I’ve done prototypes using Vue’s real-time vdom compiler to convert LiveView responses into reactive Vue templates, so I know it can be done.</p>
</blockquote>
</aside>
<p>This sounds pretty cool - I have experimented with server rendered React from phoenix - works well. Was not all that efficient in terms of diffs or anything just plain old server rendered React. I am not all that keen on having to run Node as part of the backend to make this kind of thing work though…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192067" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/54">Post #53</a>
	                </div>
	            </div>
              <div id="likers-container-192067" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192067"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #53"></div>
  </section>
</div>
    <div class="postbit" id="192083" data-post-id="192083">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bjunc" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjunc/120/16781_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bjunc
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="harmon25" data-post="54" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/48/1274_2.png" class="avatar"> harmon25:</div>
<blockquote>
<p>Not sure how much is ‘alot’ of JS…</p>
</blockquote>
</aside>
<p>I wasn’t counting “library” code towards the code count (in this context). I was referring to the amount of code needed by the developer to interact with the library code.</p>
<p>If I understand what you’re proposing though, you’re saying that this “server side redux” is the first half of what I am suggesting LiveView be broken out into; with the acknowledgement that you’d either need a UI library that talked to it (eg. something morphdom driven), or build your own. Yes?</p>
<p>If so, I think that has merits (even outside of LiveView), but it feels like a pretty different approach to the LiveView problem/solution. I wasn’t personally suggesting an entirely different approach, simply breaking the current approach up into more modular libraries.</p>
<aside class="quote no-group quote-modified" data-username="harmon25" data-post="54" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/48/1274_2.png" class="avatar"> harmon25:</div>
<blockquote>
<p>LiveView code it appears to me is highly coupled to the concept of a DOM, and the DOM heirarchy. It’s pretty much a virtual DOM in the BEAM. Not sure how the current implementation could be broken into API vs UI bits.</p>
</blockquote>
</aside>
<p>Yeah, I think that might a fair way to describe it (as far as I can see), but I’d disagree in the feasibility to decouple them. Even in cases where markup is sent from Elixir, a real-time compiler can convert this markup into framework code (eg. Vue, React, etc.), allowing your Elixir code to use Vue/React/WebComponent tags (eg. Material components).</p>
<p>Further, by separating communication from presentation, you can create components out of each “view”.  These components can have their own markup, styling, scripting, and even JS dependencies. This opens up the ability to do a lot more than just hook in, but rather swap out entire render logic. If there were “single file components” that represented each view, some of the component would execute on the server, and some would execute in the browser. You don’t really get that with the current LiveView implementation.</p>
<p>For simple / static sites, it might feel overkill (warranting a “basic” UI using something like morphdom).  But it would solve for many (if not all) of the SPA requirements.</p>
<aside class="quote no-group" data-username="harmon25" data-post="54" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/48/1274_2.png" class="avatar"> harmon25:</div>
<blockquote>
<p>I am not all that keen on having to run Node as part of the backend to make this kind of thing work though</p>
</blockquote>
</aside>
<p>I used Nuxt, so the rendering is done as part of the “UI” code (but technically a separate “server”).  Essentially, some of the work is done on page request (UI server to Elixir server), giving you the SEO benefit and hydration performance. Subsequent diffs are done in the browser. This isn’t required though. You could send static markup from Elixir.  The browser might re-render since it doesn’t know if it can trust hydration.  With a little work though, you probably could do that. Not sure if that all makes sense.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192083" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/55">Post #54</a>
	                </div>
	            </div>
              <div id="likers-container-192083" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192083"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #54"></div>
  </section>
</div>
    <div class="postbit" id="192085" data-post-id="192085">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="harmon25" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/120/1274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  harmon25
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="bjunc" data-post="55" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjunc/48/16781_2.png" class="avatar"> bjunc:</div>
<blockquote>
<p>If I understand what you’re proposing though, you’re saying that this “server side redux” is the first half of what I am suggesting LiveView be broken out into; with the acknowledgement that you’d either need a UI library that talked to it (eg. something morphdom driven), or build your own. Yes?</p>
</blockquote>
</aside>
<p>Yes exactly!</p>
<p>It is only different from LiveView imo in that it is not coupled to the DOM or any UI layer, be it HTML, React, Scenic, or some other VDOM - instead of phx-X events that are synonymous with(coupled too?) the DOM - with (arguably) difficult to reason about bubbling characteristics - the only event Redex cares about is an action with a <code>type</code> and optional <code>payload</code>… your reducers are responsible for translating that action into a state change (like a state machine) - this change can be broadcasted as a diff to wherever, instructing your UI to update!  All reducers receive the action - they do not need to act on it though - this is done via pattern matching in elixir as apposed to a switch statement in JS…</p>
<aside class="quote no-group" data-username="bjunc" data-post="55" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjunc/48/16781_2.png" class="avatar"> bjunc:</div>
<blockquote>
<p>I used Nuxt, so the rendering is done as part of the “UI” code (but technically a separate “server”). Essentially, some of the work is done on page request (UI server to Elixir server),</p>
</blockquote>
</aside>
<p>Yea I’m using this for React - <a href="https://github.com/revelrylabs/elixir_react_render" class="inline-onebox" rel="noopener nofollow ugc">GitHub - revelrylabs/elixir_react_render: React SSR Framework for Elixir · GitHub</a> - it runs some node processes in a pool on the same server as phoenix for invoking the necessary JS to render the HTML over stdio - its pretty rough - getting it all wired up and everything…and doesn’t help much reducing JS bloat, it has just about the same bloat, now on the server AND the Client <img src="https://forum.elixirforum.com/images/emoji/apple/confused.png?v=15" title=":confused:" class="emoji" alt=":confused:" loading="lazy" width="20" height="20">  And dealing with the initial render is a nightmare - like now need my API on localhost to access from within these local node processes to make the initial render worthwhile…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192085" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/56">Post #55</a>
	                </div>
	            </div>
              <div id="likers-container-192085" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192085"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #55"></div>
  </section>
</div>
    <div class="postbit" id="192100" data-post-id="192100">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="marciol" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/marciol/120/4223_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  marciol
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Interesting that using something like Clojurescript allows one to use all this ecosystem. There are even wrappers for all these React Based UI toolkits.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192100" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/57">Post #56</a>
	                </div>
	            </div>
              <div id="likers-container-192100" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192100"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #56"></div>
  </section>
</div>
    <div class="postbit" id="192104" data-post-id="192104">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="harmon25" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/120/1274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  harmon25
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I am OK with modern JS, typescript is also not bad.</p>
<p>The idea of transpiling to JS is interesting, especially if it allows a nice full stack experience without any context switching like closure/closure script.</p>
<p>I am of the opinion JavaScript is well suited for what it needs to do in the browser. Just like Erlang was built to solve a specific problem, so was JavaScript.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192104" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/58">Post #57</a>
	                </div>
	            </div>
              <div id="likers-container-192104" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192104"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #57"></div>
  </section>
</div>
    <div class="postbit" id="192175" data-post-id="192175">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="cnck1387" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  cnck1387
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group quote-modified" data-username="bjunc" data-post="32" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bjunc/48/16781_2.png" class="avatar"> bjunc:</div>
<blockquote>
<p>Plenty of turn-key UI libraries. For instance, Material components exist for Vue, React, etc… I keep seeing these really primitive LiveView UIs with basic CSS. That’s just not what a modern app looks like. Are we going to build a multi-select, token dropdown menu that support slots, is accessible, and mobile friendly in LiveView?</p>
</blockquote>
</aside>
<p>Right and I find that most theme authors or toolkits like Tailwind UI are catered towards Vue, React or AlpineJS.</p>
<p>There’s a bunch of stuff that’s best suited towards client side JS like menus, drop down menus, sidebar menus, tooltips, popovers, copying to clipboard, the visual element of drag / drop, accordions, toggling visibility on simple elements without state and a ton of other little things like maybe wanting to show the character count of a field that’s being typed into or showing the preview color of a hex value where you might not necessarily want to make a server round trip.</p>
<p>And even if you follow the pattern of server rendered templates with sprinkles of javascript, even those sprinkles add up to be enough JS where you want something besides a jumbled mess of jquery and bare bones ES6 features. I think even with LV you’ll end in this same spot.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192175" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/59">Post #58</a>
	                </div>
	            </div>
              <div id="likers-container-192175" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192175"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #58"></div>
  </section>
</div>
    <div class="postbit" id="192179" data-post-id="192179">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dorgan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/120/22107_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dorgan
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m doing a Phoenix + Custom Elements frontend right now. It’s not messy, really. Except for the part of having templates split between phoenix and js. That disconnect can be hard to tackle.<br>
To be more concrete, say you have a blog article:</p>
<pre data-code-wrap="erb"><code class="lang-erb">&lt;article class="blog-article" data-article-id="&lt;%= @article.id %&gt;"&gt;
  &lt;header&gt;
    &lt;!-- some user data --&gt;
    &lt;some-custom-menu&gt;&lt;/some-custom-menu&gt;
  &lt;/header&gt;
  &lt;section class="article-body&gt;
    &lt;%= @article.body %&gt;
  &lt;/section&gt;
&lt;/article&gt;
</code></pre>
<p>Now imagine that <code>some-custom-menu</code> has an option that modifies the structure of the article to a variant that is also specified in phoenix templates(it adds tags, it changes some setting(like “sensible content” on a tweet), you get the idea). Even if you use a builtin extend(like <code>article is="my-article-component"&gt;</code>, both component and phoenix need to know about the template, which doesn’t seem like a big deal, but when you have a good bunch of them and you need to update them in two different places, it’s really easy to mess up.</p>
<p>With an SPA you don’t have this kind of issues(your page just works HORRIBLY in a low end device or a pc with outdated hardware, althought this also varies notably not only with complexity, but with the ammount of content you need to update -ie infinite scrolling-), but then you need to run an additional node backend to render it serverside or you lose SEO benefits(googlebot is not the only crawler ot there). And that’s hacky.</p>
<p>The “data diffs in the backend and spa or whatever on the frontend” sounds interesting, but the point would be to close that disconnect while letting the server render stuff, which LiveView achieves in many cases.</p>
<p>Personally, I wouldn’t have “pre-made components like material ui” as a metric, because when I started with VueJS the complain was that there was a lack of component uis and it wasn’t wise to pick it for a new project. Same for svelte until a few months ago. First comes the solution, only then one would care about component libraries if they’re so important.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192179" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/60">Post #59</a>
	                </div>
	            </div>
              <div id="likers-container-192179" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192179"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #59"></div>
  </section>
</div>
    <div class="postbit" id="192183" data-post-id="192183">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="LostKobrakai" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/LostKobrakai/120/3072_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  LostKobrakai
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dorgan" data-post="60" data-topic="34743">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/48/22107_2.png" class="avatar"> dorgan:</div>
<blockquote>
<p>Now imagine that <code>some-custom-menu</code> has an option that modifies the structure of the article to a variant that is also specified in phoenix templates(it adds tags, it changes some setting(like “sensible content” on a tweet), you get the idea). Even if you use a builtin extend(like <code>article is="my-article-component"&gt;</code> , both component and phoenix need to know about the template, which doesn’t seem like a big deal, but when you have a good bunch of them and you need to update them in two different places, it’s really easy to mess up.</p>
</blockquote>
</aside>
<p>Most of that comes down do the problems of distributed state. If article is modified by both the server and the client you need some way to consolidate state. Ultimately you either need CRDTs or some other means of getting rid of conflicts between concurrent changes. While there’s e.g. automerge on the js side of things I don’t know of any CRDT implemented in elixir and js besides maybe phoenix presence.</p>
<p>That’s also the reason why I personally don’t see the problems with dropdowns and other similar UI components. Their state doesn’t overlap the state on the server. Say I have a dropdown, where the list of links is handled by liveview. The state for list items is completely separate from if the dropdown is open. The open/close state should imo never be handled by liveview, while the list of items needs the server for getting updated. That’s why the alpine.js integration with liveview works so well – whenever liveview updates alpine does apply it’s local changes on top. One likely could do the same with react or vue or whatever, but there’s just not many people using those libraries like that.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192183" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/61">Post #60</a>
	                </div>
	            </div>
              <div id="likers-container-192183" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192183"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #60"></div>
  </section>
</div>
    <div class="postbit" id="192185" data-post-id="192185">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="harmon25" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harmon25/120/1274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  harmon25
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think the emphasis on SEO, and it being an argument against using an SPA is not at all universal.</p>
<p>Depending on the target audience for the application, I.E a business app vs something like twitter, github or a forum…SEO is not really important. If the app is behind a login page, sacrificing UX for the sake of SEO is not really defensible.</p>
<p>That is the purpose of a marketing site, which promotes the features, and problems your app is trying to solve. The marketing site will be completely static, and have the SEO nobs dialed to the max, with a link to login to the actual app.</p>
<p>In my case, this is pretty much 100% of what I build…so moving rendering to the server for anything but improving metrics like <a href="https://web.dev/largest-contentful-paint/" rel="noopener nofollow ugc">Largest Contentful Paint</a> is only costing the business compute - as mentioned before, client side rendering is free distributed computing…</p>
<p>And if you think the app you are building is going to be Twitter, GitHub scale, and actually see meaningful organic growth from SEO - you are already a bit of a unicorn, imho.</p>
<p>One way I have dodged the slow paint and abrupt rendering of an SPA is to apply some full page inline CSS animation on the served HTML. Allowing the browser to immediately show some indeterminate loading screen.  This is pretty common for say a desktop/mobile application to require a loading screen or indicator before actually launching - I do not think this is bad UX, and actually expected if the App has enough data/interactivity…</p>
<p>EDIT: Also, pretty sure LiveView would not work that great for an App like Twitter, or GitHub - or at least at that scale. So say you did build the next <code>Socially Responsible Twitter</code> with LiveView - wonder how the engineering would evolve…I imagine the thought of an SPA would come up in the board room because the servers are starting to cost a bit too much. This same argument applies to the Redex library I have posted about - there is definitely a threshold of scale that likely means server side in memory state is a bad idea…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="192185" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/phoenix-liveview-vs-spa/34743/62">Post #61</a>
	                </div>
	            </div>
              <div id="likers-container-192185" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="192185"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #61"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/34743/load_more?page=7">Load more posts (30 remaining)</a>
</div></template></turbo-stream>