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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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>Before dealing with the problem of macros, I think there is something else that deserves some attention. Some parts of a template are evaluated at runtime but they never change. For example, the CSRF token of a form (<code>&lt;%= Plug.get_csrf_token() %&gt;</code>), translations done with gettext (<code>&lt;%= gettext "Hello world" %&gt;</code>), among others.</p>
<p>Having to send these over the network seems very wasteful. These should only be rendered on the initial page load and treated as static afterwards.</p>
<p>I should have a new marker (for example: <code>&lt;%| ... %&gt;</code>) for text that never changes like in the examples above.</p>
<p>So this means there will be static terms (raw binaries), fixed terms (static binaries + expressions that never change) and dynamic/reactive terms (terms that are re-rendered when something changes).</p>
<p>EDIT: I’m aware this is moving me away from the focus on macro expansion, and it also complicates the architecture, but it’s a very high yield optimization, so I’ll solve it first.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98578" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/32">Post #31</a>
	                </div>
	            </div>
              <div id="likers-container-98578" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98578"
                     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 #31"></div>
  </section>
</div>
    <div class="postbit" id="98599" data-post-id="98599">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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>I have some free time now, but I’m away from the computer, so I’ll sketch my thoughts about actually sending the dynamic data into the client.</p>
<p>Dynamic data is a list of iolists. The length of the list is fixed. This list must be encoded in the client somehow. JSON would not be a bad choice, because encoding a list as a JSON array has a small overhead.</p>
<p>Could we do it using a stream protocol to avoid allocating memory for the binary that encodes the list? Can we reuse the default encoder for Phoenix channels? If so, then we only need to pass the list of binaries and Phoenix will take care of the rest. But that requires us to render the iolists inside the list into binaries, which allocates memory.</p>
<p>I should take a look at how JSON encoders actually handle iolists. My guess is that they don’t, because an iolist is indistinguishable from a deeply nested json array.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98599" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-98599" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98599"
                     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 #32"></div>
  </section>
</div>
    <div class="postbit" id="98600" data-post-id="98600">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>To me that’s a complete separate problem. We will need to figure out a light-weight protocol to send data to the client but that is a separate problem than the engine one. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98600" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/34">Post #33</a>
	                </div>
	            </div>
              <div id="likers-container-98600" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98600"
                     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 #33"></div>
  </section>
</div>
    <div class="postbit" id="98601" data-post-id="98601">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="34" data-topic="16533">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/48/1787_2.png" class="avatar"> josevalim:</div>
<blockquote>
<p>To me that’s a complete separate problem.</p>
</blockquote>
</aside>
<p>Yes, I agree completely, it’s just something I thought about a while ago and had some free time to write. My main focus is the engine itself. You or some other network whiz can probably think of something much more efficient (for example, sending strings as a flat binary separated by null bytes or something like that; as long as the Javascript on the other side can make sense of it you can use whatever you want).</p>
<p>My priorities are still the two I’ve outlined above:</p>
<ol>
<li>Add support for fixed template segments (i.e. <code>&lt;%| this_will_be_rendered_only_once %&gt;</code>) and</li>
<li>Expand and optimize macros (is possible in a semantically correct way)</li>
</ol> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98601" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/35">Post #34</a>
	                </div>
	            </div>
              <div id="likers-container-98601" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98601"
                     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 #34"></div>
  </section>
</div>
    <div class="postbit" id="98603" data-post-id="98603">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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>Going back to the “fixed segments”, one might ask why I’m using <code>&lt;%| ... %&gt;</code> as the equivalent to <code>&lt;%= ... %&gt;</code> in “normal” phoenix templates. Maybe it would make sense to use <code>&lt;%= ... %&gt;</code> for the fixed parts (the same semantics as the normal templates) and <code>&lt;%| ... %&gt;</code>  for the dynamic/reactive parts (which is a concept we don’t have in “normal” templates).</p>
<p>I’m doing this for two reasons:</p>
<ol>
<li>It’s more obvious for the user: if the user wants Reactive (= Undead) templates, most of the content will be reactive, so it makes sense to use the “common” marker instead of the weird one.</li>
<li>(and most important) The fixed segments will be rendered only once, and won’t be available when rendering the dyamic parts. This means that fixed segments must have no side effects, including but not limited to assigning variables…)</li>
</ol>
<p>That is, you can’t do this:</p>
<pre><code class="lang-plaintext">&lt;%| f = slow_computation_i_dont _want_to_repeat_each_time() %&gt;
&lt;%= do_stuff(f) %&gt;
</code></pre>
<p>Because <code>f</code> won’t be available on the dynamic template! So using the fixed segments require some care on behalf of the user.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98603" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/36">Post #35</a>
	                </div>
	            </div>
              <div id="likers-container-98603" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98603"
                     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 #35"></div>
  </section>
</div>
    <div class="postbit" id="98618" data-post-id="98618">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="tmbb" data-post="32" data-topic="16533">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>I should have a new marker (for example: <code>&lt;%| ... %&gt;</code> ) for text that never changes like in the examples above.</p>
</blockquote>
</aside>
<p>Drab also has a special indicator (I think <code>&lt;%/</code>?) for such things that should only ever be sent on initial load.  <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<aside class="quote no-group" data-username="tmbb" data-post="36" data-topic="16533">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>Because <code>f</code> won’t be available on the dynamic template! So using the fixed segments require some care on behalf of the user.</p>
</blockquote>
</aside>
<p>Hmm, I wonder how drab handles this case…</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98618" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/37">Post #36</a>
	                </div>
	            </div>
              <div id="likers-container-98618" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98618"
                     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 #36"></div>
  </section>
</div>
    <div class="postbit" id="98623" data-post-id="98623">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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">
								<aside class="quote no-group" data-username="OvermindDL1" data-post="37" data-topic="16533">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Hmm, I wonder how drab handles this case…</p>
</blockquote>
</aside>
<p>Personally I’m not planning on supporting this at all. I’ll look at what Drab does.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98623" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/38">Post #37</a>
	                </div>
	            </div>
              <div id="likers-container-98623" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98623"
                     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 #37"></div>
  </section>
</div>
    <div class="postbit" id="98624" data-post-id="98624">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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">
								<aside class="quote no-group" data-username="OvermindDL1" data-post="37" data-topic="16533">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Drab also has a special indicator (I think <code>&lt;%/</code> ?) for such things that should only ever be sent on initial load. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
</blockquote>
</aside>
<p>It’s normal that we’ll converge into similar solutions. The problems are very similar.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98624" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/39">Post #38</a>
	                </div>
	            </div>
              <div id="likers-container-98624" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98624"
                     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 #38"></div>
  </section>
</div>
    <div class="postbit" id="98753" data-post-id="98753">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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>I already know how I want to expand macros (I’ll publish the code when it’s ready), but I’m having some troubles in thinking on how to turn <code>form_for</code> into a macro that outputs something useful… Ideally, one would have a compatible of <code>form_for</code> (which is a function) but which does something useful at compile time and expands into a mostly static template.</p>
<p>Until I have something concrete on how to optimized <code>form_for</code>, I’ll put most of the rest on hold. The most dynamic arts of websites are often forms, and it’s important that dynamic features in forms are as efficient as possible.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98753" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/40">Post #39</a>
	                </div>
	            </div>
              <div id="likers-container-98753" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98753"
                     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 #39"></div>
  </section>
</div>
    <div class="postbit" id="98784" data-post-id="98784">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <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">
								<h3><a name="p-98784-major-changes-1" class="anchor" href="#p-98784-major-changes-1" aria-label="Heading link" rel="nofollow"></a>Major Changes</h3>
<p>I’ve been more or less blinded by the idea that the EEx templates should return something that’s similar to a quoted expression. As <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a> said some time ago, this is a mistake. I’ve lost a couple hours which I’ll never get back for not listening to his advice. This tells me I should following to his advice next time. Or not, who knows…</p>
<p>So this is how it will work now:</p>
<p>The engine will no longer compile the text into a real quoted expression. I’ll make it so that it compiles into a structure made from tuples and lists of 2-tuples. I like to think of 2-tuples as algebraic data types, and it would help if Elixir supported real algebraic data types, but well, we have to make do with what we have.</p>
<p>The “datatype” of the intermediate EEx templates would be the following:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:undead_eex,
  [
    # static text
    {:static, "static binary"},
    # &lt;%= ... %&gt;
    {:dynamic, expr1},
    # &lt;% ... %&gt;
    {:dynamic_no_output, expr2}
    # &lt;%| ... %&gt;
    {:fixed, expr2}
    ...
  ]}
</code></pre>
<p>The critical thing is that I can nest an <code>{:undead_eex, _}</code> template inside the <code>{:dynamic, _}</code> constructor. This nested template could be the result of expanding a macro inside a <code>:dynamic</code> segment. For example, I could have:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:undead_eex,
  [
    segment1,
    segment2,
    {:dynamic, expression_with_a_macro},
    segment3,
    segment4
  ]}
</code></pre>
<p>After expanding the macro (inside the UndeadEEx engine or in a postprocessing step), this could return the following template:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:undead_eex,
  [
    segment1,
    segment2,
    {:dynamic, {:undead_eex, contents}}
    segment3,
    segment4
  ]}
</code></pre>
<p>I can statically simplify this into:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:undead_eex,
  [
    segment1,
    segment2
  ] ++ contents ++ [
    segment3,
    segment4
  ]}
</code></pre>
<p>I am now compiling the text into such an abstract format, which preserves interesting semantic distinctions between the several types of segments (instead of a quoted expression, which kinda blends everything together in executable Elixir code).</p>
<p>I can apply valid algebraic transformations to this structure in order to optimize it further. The transformation above is an example (actually the only one I can think of right now). The following expressions are equivalent:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:dynamic, {:undead_eex, contents}} # is equivalent to...
contents
</code></pre>
<p>It’s possible that there are other valid transformations I can apply, but the important is the idea.</p>
<p>This is all a bit abstract, so let me show how this can be quite useful.</p>
<h4><a name="p-98784-a-template-is-a-2-tuple-2" class="anchor" href="#p-98784-a-template-is-a-2-tuple-2" aria-label="Heading link" rel="nofollow"></a>A template is a 2-tuple</h4>
<p>As I said, a <em>compiled template</em> is a 2-tuple of the form <code>{:undead_eex, contents}</code>. Templates are fed into the Engine as text files. A compiled template is the “raw” result of compiling a text file with the <code>UndeadEngine</code>.</p>
<p>This compiled template is not very useful by itself. It’s not a quoted expression which you splice into Elixir’s AST to get some executable code. You should think of it as an intermediate representation in a compiler</p>
<h4><a name="p-98784-templates-can-be-nested-inside-each-other-3" class="anchor" href="#p-98784-templates-can-be-nested-inside-each-other-3" aria-label="Heading link" rel="nofollow"></a>Templates can be nested inside each other</h4>
<p>Because a template is simply a data structure, it’s obvious we can nest them inside each other:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:undead_eex,
  [
    ...,
    {:dynamic, {:undead_eex,
      [
        {:dynamic, {:undead_eex, ...}}
      ]}},
      ...
  ]}
</code></pre>
<p>When we have nested templates, we can always apply the rule above to flatten them into a single template.</p>
<h4><a name="p-98784-we-can-define-reusable-widgets-4" class="anchor" href="#p-98784-we-can-define-reusable-widgets-4" aria-label="Heading link" rel="nofollow"></a>We can define reusable widgets</h4>
<p>We can define reusable widgets as macros. Those macros will be expanded into templates (which are a data structure and not a quoted expression representing executable code!).</p>
<p>If you have a <code>my_widget(arg1)</code> macro inside a <code>:dynamic</code> segment, it will be expanded. If the result of the expansion is a valid compiled template (i.e. <code>{:undead_eex, ...}</code>), it can be flattened into the parent template.</p>
<p>This is great for optimization, because we can merge adjacent binaries.</p>
<h4><a name="p-98784-some-widgets-in-phoenix_html-can-be-reimplemented-as-macros-5" class="anchor" href="#p-98784-some-widgets-in-phoenix_html-can-be-reimplemented-as-macros-5" aria-label="Heading link" rel="nofollow"></a>(Some) Widgets in <code>phoenix_html</code> can be reimplemented as macros</h4>
<p>The <code>phoenix_html</code> package defines a number of widgets, implemented as functions. For example:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; import Phoenix.HTML.Tag
Phoenix.HTML.Tag
iex&gt; tag(:input, [id: "user_name", name: "user[name]", type: "text", value: "value"]) |&gt; Phoenix.HTML.safe_to_string()
"&lt;input id=\"user_name\" name=\"user[name]\" type=\"text\" value=\"value\"&gt;"
</code></pre>
<p>We can reimplement the <code>tag</code> widget as a macro that expands into a complete <code>{:undead_eex, ...}</code> template, which will be embedded in a larger template and ultimately flattened into the larger template (for further optimization). For example, let’s try to relicate the above:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; import PhoenixUndeadView.Widgets
PhoenixUndeadView.Widgets
iex&gt; Macro.expand(quote(do: tag(:input, [id: "user_name", name: "user[name]", type: "text", value: "value"])), __ENV__)
{:undead_eex,
 [
   static: "&lt;input id=\"user_name\" name=\"user[name]\" type=\"text\" value=\"value\"&gt;"
 ]}
</code></pre>
<p>The output is pretty much the same (except that it is properly tagged as a compiled template should be). But values in input tags are often dynamic. So let’s make it dynamic:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; Macro.expand(quote(do: tag(:input, [id: "user_name", name: "user[name]", type: "text", value: @user.name])), __ENV__)
{:undead_eex,
 [
   static: "&lt;input id=\"user_name\" name=\"user[name]\" type=\"text\" value=\"",
   dynamic: {:html_escape,
    [context: PhoenixUndeadView.Widgets, import: Phoenix.HTML],
    [
      {{:., [],
        [
          {:@, [context: Elixir, import: Kernel],
           [{:user, [context: Elixir], Elixir}]},
          :name
        ]}, [], []}
    ]},
   static: "\"&gt;"
 ]}
</code></pre>
<p>We get a much more interesting compiled template, which follows the main design rules of <code>PhoenixUndeadView</code></p>
<ol>
<li>What is static is always static</li>
<li>What is dynamic is always dynamic</li>
</ol>
<p>The above would be transformed so that <code>@user.name</code> becomes something like <code>assigns[:user][:name]</code> or something like that, but the <code>UndeadEngine</code> already handles that part.</p>
<p>The fact that <code>tag</code> is now a macro that receives literal AST terms allows me to split the attribute list into static and dynamic parts and optimize it by merging all static parts together. This is a simple but very high-yield optimization.</p>
<p>If this macro is expanded inside a larger template, the static part at the beginning and the end can be merged with other binaries, thus increasing efficiency.</p>
<p>There <em>might</em> still be some problems with variable scope , but I’m pretty happy with the general idea. I think there shuoldn’t be any actual problems, but I haven’t tested this properly yet in the “real world”.</p>
<h4><a name="p-98784-things-might-get-even-more-succinct-with-sigils-6" class="anchor" href="#p-98784-things-might-get-even-more-succinct-with-sigils-6" aria-label="Heading link" rel="nofollow"></a>Things might get even more succinct with sigils</h4>
<p>I have reimplemented the <code>tag</code> template by creating the tuples above “by hand”.<br>
If we define a <code>~U""</code> sigil (from <strong>u</strong>ndead) which returns a compiled template, we might define widgets in a more natural way by making them macros that return the sigil.</p>
<p>That’s not something I’d do with the <code>tag</code> macro because it needs to support a variable number of attributes, but it might make sense in other cases where everything has a fixed number of arguments.</p>
<h4><a name="p-98784-plans-for-the-future-7" class="anchor" href="#p-98784-plans-for-the-future-7" aria-label="Heading link" rel="nofollow"></a>Plans for the future</h4>
<p>I’ll reimplement most widgets in <code>Phoenix.HTML</code> as macros and reimplement the engine so that it can make use of these templates.</p>
<p>I still haven’t found a good way to reimplement <code>form_for</code>, one can get good results with something like:</p>
<pre data-code-wrap="plaintext"><code class="lang-plaintext">&lt;% form = FormData.to_form(@changeset, options) %&gt;
&lt;%= form_tag "/url", method: "post" do %&gt;
  &lt;%= text_input(form, :name) %&gt;
  &lt;%= text_input(form, :surname) %&gt;
&lt;% end %&gt;
</code></pre>
<p>where <code>form_tag/3</code> and <code>text_input/2</code> are macros. It’s possible that even reimplementing <code>form_tag/3</code> might be too difficult in a sane way (probably not, Ecto does much crazier things with macro than what I’m doing here). In that case we can go back to my dirty proposal of having <code>open_form()</code> and <code>close_form()</code> macros which act as ordinary segments.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="98784" 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/phoenixundeadview-lets-discuss-optimization-possibilities-for-something-like-phoenix-liveview/16533/41">Post #40</a>
	                </div>
	            </div>
              <div id="likers-container-98784" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="98784"
                     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 #40"></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/16533/load_more?page=5">Load more posts (101 remaining)</a>
</div></template></turbo-stream>