<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="100587" data-post-id="100587">
  <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="61" 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>(Very boring post asking for naming feedback)</p>
</blockquote>
</aside>
<p>Lol, but they tend to be fun!</p>
<aside class="quote no-group" data-username="tmbb" data-post="61" 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’ve changed <code>Segment.undead_container(segments, meta)</code> to <code>Segment.container(segments, meta)</code> , because I might change the <code>Undead</code> namespace to something else.</p>
</blockquote>
</aside>
<p>Yeah, no need to put namespace names in function calls.</p>
<aside class="quote no-group" data-username="tmbb" data-post="61" 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><code>Ghost</code> , surprisingly free</p>
</blockquote>
</aside>
<p>Need something for that!  ^.^</p>
<aside class="quote no-group" data-username="tmbb" data-post="61" 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>This means it should be easy to swap the imports in your Phoenix project, should you choose to use Vampyre templates</p>
</blockquote>
</aside>
<p>Ah, that’s a good usage 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="100587" 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/62">Post #61</a>
	                </div>
	            </div>
              <div id="likers-container-100587" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="100587"
                     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>
    <div class="postbit" id="100614" data-post-id="100614">
  <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>Assuming this project is named Vampyre ther will obviously be a <code>~V</code> so that you can do this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmacro my_html_helper(x, y, z) do
  ~V"""
  Somethin something &lt;%= x %&gt;
  Blah blah &lt;%= y + z %&gt;
  """
end
</code></pre>
<p>This will be compiled into a ready-to-use <code>Segment.container()</code>, which will optimize properly when inside a vampyre template.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="100614" 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/63">Post #62</a>
	                </div>
	            </div>
              <div id="likers-container-100614" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="100614"
                     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 #62"></div>
  </section>
</div>
    <div class="postbit" id="100618" data-post-id="100618">
  <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">
								<p>Super convenient!  As such a usage should be.  ^.^</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="100618" 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/64">Post #63</a>
	                </div>
	            </div>
              <div id="likers-container-100618" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="100618"
                     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 #63"></div>
  </section>
</div>
    <div class="postbit" id="101040" data-post-id="101040">
  <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’ve decided I’ll separate the template engine, HTML widgets into the Vampyre package, so that they cane be used in Phoenix. I should probably benachmark it firstc, but it makes sense to benchmark the whole pipeline. Unfortunately, when Phoenix compiles templates, it doesn’t give me access to the compilation environment. I need such access because I need to have control over macro expansion inside the templates. This means I’ll need to write a <code>Vampyre.View</code> module that compiles Vampyre templates correctly. This is a question of copying and pasting some files from phoenix and changing 2 or 3 functions. It would be cool if the <code>Phoenix.Template.compile/2</code> function could be called with the <code>__ENV__</code> of the view module, because it looks that would avoid all this work.</p>
<p>If I decide to write an UndeadView, or an integration with Drab, I’ll do it on top of the Vampyre package.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101040" 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/65">Post #64</a>
	                </div>
	            </div>
              <div id="likers-container-101040" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101040"
                     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 #64"></div>
  </section>
</div>
    <div class="postbit" id="101052" data-post-id="101052">
  <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>It turns out I can work around that limitation without rewriting <code>Phoenix.View</code>. I just have to wrap the quoted expression in a macro. At macro exapnsion time, the wrapper macro can fetch the environment, expand its arguments and optimize the quoted expression.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101052" 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/66">Post #65</a>
	                </div>
	            </div>
              <div id="likers-container-101052" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101052"
                     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 #65"></div>
  </section>
</div>
    <div class="postbit" id="101139" data-post-id="101139">
  <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>One of tbe problems with Vampyre templates is that while they are allow “normal” HTML widgets inside them (they just can’t optimize them), Phoenix’s own engine doesn’t accept Vampyre segments. It accepts fully compiled Vampyre templates of course, but not the incompletely compiled Vampyre templates that can be optimized. In truth, optimizing rendered Vampyre templates is probbaly not that hard, and I should look into it.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101139" 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/67">Post #66</a>
	                </div>
	            </div>
              <div id="likers-container-101139" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101139"
                     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 #66"></div>
  </section>
</div>
    <div class="postbit" id="101152" data-post-id="101152">
  <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-101152-benchmarks-1" class="anchor" href="#p-101152-benchmarks-1" aria-label="Heading link" rel="nofollow"></a>Benchmarks</h3>
<p>I have uploaded an example project, so that I can run “more realistic” benchmarks. You can find the repo <a href="https://github.com/tmbb/vampyre_app" rel="noopener nofollow ugc">here</a>. The benchmarks below are the result of rendering the form generated by the phoenix generators for a dummy User resource. This means the template is probably representative of “real world” templates.</p>
<p>You can run these benchmarks yourselfby running the following command in the repo above.</p>
<pre><code class="lang-plaintext">mix run benchee/main.exs
</code></pre>
<p>The results are:</p>
<pre><code class="lang-plaintext">Benchmarking phoenix...
Benchmarking vampyre...

Name              ips        average  deviation         median         99th %
vampyre      123.41 K        8.10 μs   ±231.37%           7 μs          25 μs
phoenix       10.13 K       98.69 μs    ±20.93%          95 μs      180.18 μs

Comparison:
vampyre      123.41 K
phoenix       10.13 K - 12.18x slower
</code></pre>
<p>This shows that in the case of forms, Vampyre templates are about <strong>12x</strong> faster than the default phoenix templates. The absolute time differences are tiny, of course, because we’re talking about microseconds, but the improvement is quite impressive.</p>
<p>I still haven’t implemented all the HTML widgets implemented by <code>phoenix_html</code>. In fact, I have implemented just enough to be able to render the output of the Phoenix generators, but most of the rest can be implemented on top of what I already have. This is not one of those cases where “the code is simple and fast because implementing the last 10% takes the last 90% of the code/work”, because the work my widgets do it at compile-time. Although my incomplete implementation of the HTML widgets is already more complex than the one in <code>phoenix_html</code> (in terms of lines of code, and concepts I introduce throughout the code base) the complexity happens at compile time with the goal of making things fast at runtime.</p>
<h3><a name="p-101152-am-i-doing-something-dirty-to-get-these-benchmarks-2" class="anchor" href="#p-101152-am-i-doing-something-dirty-to-get-these-benchmarks-2" aria-label="Heading link" rel="nofollow"></a>Am I doing something dirty to get these benchmarks?</h3>
<p>Yes. The implementation of <code>form_for</code> that makes it fast inlines a function call by introducing a hygienic variable in the global scope of the template. This doesn’t change the semantics of the template too much because the variable is inaccessible to the user-written code. But it is an issue if you nest <code>form_for</code> inside another <code>form_for</code>. This is not valid HTML but there might be reasons why you’d want to do that. In case the above isn’t scary enough, I reproduce the code here:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def make_form_for(form_data, action, options, fun) do
    {:fn, _,
     [
       {:-&gt;, _,
        [
          [arg],
          body
        ]}
     ]} = fun

    validate_fun_arg(arg)
    hygienic_var = hygienize_var(arg)
    substituted_body = substitute(body, arg, hygienic_var)

    open_form = Tag.make_form_tag(action, options)

    hygienic_assignment =
      quote do
        unquote(hygienic_var) = FormData.to_form(unquote(form_data), unquote(options))
      end

    close_form = Segment.static("&lt;/form&gt;")

    contents = [
      open_form,
      Segment.support(hygienic_assignment),
      substituted_body,
      close_form
    ]

    Segment.container(:lists.flatten(contents))
  end
</code></pre>
<p>I’m pattern matching  on the AST of the function in the form to get the variable given as argument, an then, in the bpdy of the function, <em>I substitute the old variable by a new one, and dump the body of the function into the global scope of the template</em>. This avoids a function call and flattens the segments list, so that I can merge them together.</p>
<p>I think I can the issue with nested forms by doing even dirtier things with the process dictionary (I can safely assume that the template will be compiled by a single process) and using the variable’s <code>:counter</code> in the metadata to make variables even more distinct from each other.</p>
<h3><a name="p-101152-whats-missing-3" class="anchor" href="#p-101152-whats-missing-3" aria-label="Heading link" rel="nofollow"></a>What’s missing</h3>
<p>I still haven’t implemented all HTML widgets. Also, I haven’t even implemented all widgets correctly. Because I’m aggressively optimizing everything, there is some heavy-duty case analysis on the widget-generating macros/functions. For example, <code>tag(:input, name: "user[name]", id: "user_name")</code> takes advantage of the fact that all attrbutes are static to render everything into a static binary (which can be merged with the previous or next binaries). However, if we change the above to  <code>tag(:input, name: @name, id: "user_name")</code>, the expression will be rendered into a static part, followed by a dynamic part, followed by another static part. If the user writes instead <code>tag(name, attrs)</code>, then this is a case I don’t even handle yet!</p>
<p>So I have yet to implement the “maximally dynamic” versions of my widgets. In such cases I might just fall back to Phoenix’s implementation, but there are still some performance optimizations to be had. For example, even if both the tag name and the attributes are purely dynamic, we know the rendered value starts with <code>"&lt;"</code> and ends with <code>"&gt;"</code>, which can be merged into the previous binaries.</p>
<h3><a name="p-101152-is-this-worth-it-4" class="anchor" href="#p-101152-is-this-worth-it-4" aria-label="Heading link" rel="nofollow"></a>Is this worth it?</h3>
<p>To render normal templates, I don’t know. As I said above, the relative differences in performance are impressive (I wasn’t expecting such a difference), but rendering templates is already so fast that maybe it doesn’t really matter. And all the complexity can introduce bugs, security vulnerabilities, etc.</p>
<p>To use with something like Drab or LiveView, or something like that, where being able to siolate the static from the dynamic parts of the templates is critical (to minimize sending data over the network), this is definitely worth it.</p>
<p>Even if for that reason alone, I plan on continuing to work on Vampyre until it has feature-parity with <code>phoenix_html</code>. Vampyre is already a drop-in replacement for <code>phoenix_html</code> (by changing two lines of code in your project you magically get Vampyre templates for free), and if the user decides to use  Vampyre templates for something like LiveView or Drab, then it makes sense to use Vampyre templates to render the “normal” views.</p>
<p>It will take some time, of course, because I’m not only implementing template renderers. I’m actually implementing an optimizing compiler for template renderers, and the default widgets need to play well with the compiler.This means that everything is about 5x harder to write than the naïve versions in <code>phoenix_html</code>. It gets easier as I get further away, because I can implement some widgets on top of other widgets. For example, I’m implementing the <code>form_for</code> widget on top of the <code>tag</code> widget.</p>
<p>EDIT: I believe I’m doing everything right when defining the renderer functions for both Vampyre and Phoenix templates. I’ve copied the approach taken by Phoenix itself, so I guess I’m not being unfair to the Phoenix templates.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101152" data-batch-url="/posts/batch_likers">
                        6
                      </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/68">Post #67</a>
	                </div>
	            </div>
              <div id="likers-container-101152" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101152"
                     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 #67"></div>
  </section>
</div>
    <div class="postbit" id="101153" data-post-id="101153">
  <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>The demo project above (where the benchmarks are defined) uses Vampyre templates by default. That way, you can see that Vampyre is already an incomplete drop-in replacement for <code>phoenix_html</code> (although Vampyre depends on <code>phoneix_html</code> for some utilities for escaping HTML and other things). The only changes required to support Vampyre templates in a phoenix project are the following:</p>
<ol>
<li>
<p>Add <code>:vampyre</code> to your list of dependencies (<code>:vampyre</code> is not on hex yet, because it’s still missing a lot of things, so you have to add it from GitHub or as a path dependency).</p>
</li>
<li>
<p>In the <code>config/config.exs</code> file, add the following line (which causes Phoenix to compile templates using the Vampyre compiler):</p>
</li>
</ol>
<pre data-code-wrap="elixir"><code class="lang-elixir">config :phoenix, :template_engines, eex: Vampyre.Template.EExEngine
</code></pre>
<p>Finally, inside your ProjectWeb module, replace:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def view do
    quote do
      # ...
      # Use all HTML functionality (forms, tags, etc)
      use Phoenix.HTML
      # ...
    end
  end
</code></pre>
<p>by</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def view do
    quote do
      # ...
      # Use all HTML functionality (forms, tags, etc)
      use Vampyre.HTML
      # ...
    end
  end
</code></pre>
<p>The above makes the (API-compatible) macros from the <code>vampyre</code> package available in your views, so that you use the self-optimizing widgets instead of the slower widgets from <code>phoenix_html</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101153" 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/69">Post #68</a>
	                </div>
	            </div>
              <div id="likers-container-101153" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101153"
                     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 #68"></div>
  </section>
</div>
    <div class="postbit" id="101154" data-post-id="101154">
  <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>This series of posts is very interesting from a “historical” perspective on the Vampyre project. Even I like to re-read them sometimes, but I think I should write something more definitive, like a blog post not that things are stabilizing somehow. Even for people who are completely uninterested in rendering HTML templates can learn some interesting things from it. The Vampyre project touches some interesting areas, such as:</p>
<ul>
<li>How phoenix actually renders templates</li>
<li>Tricks to get performance on the BEAM (iolists are <em>fast</em>, but not <em>that fast</em>; also, function calls come with a cost)</li>
<li>Using macros to avoid doing at runtime what you can do at compile-time</li>
<li>Manipulating Elixir quoted expressions</li>
<li>Working with EEx engines (the documentation we have now is somewhat lacking; the hexdocs could use some love)</li>
<li>The importance of a smart intermediate representation in a compiler (don’t try to output the final code in a single step)</li>
<li>Using macros to delay expression evaluation</li>
<li>Inlining functions without explicit compiler support</li>
</ul>
<p>I think I should write something in the line of the following (amazing!) blog post: <a href="https://www.bignerdranch.com/blog/elixir-and-io-lists-part-2-io-lists-in-phoenix/" rel="noopener nofollow ugc">https://www.bignerdranch.com/blog/elixir-and-io-lists-part-2-io-lists-in-phoenix/</a>. Which by the way was the major source of inspiration for the whole Vampyre project. After all, the big idea for this came from that post: <strong>Phoenix automatically and universally applies this simple view caching strategy: the static parts of our template are always cached. The dynamic parts are never cached. The cache is invalidated if the template file changes. The end.</strong> The Vampyre project just takes that idea into the next level, by aggressively merging the static parts of the template.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101154" data-batch-url="/posts/batch_likers">
                        4
                      </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/70">Post #69</a>
	                </div>
	            </div>
              <div id="likers-container-101154" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101154"
                     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 #69"></div>
  </section>
</div>
    <div class="postbit" id="101158" data-post-id="101158">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>just chiming in to say I’ve been following these posts rather closely and learning a lot, thanks!  Right now I’m really tempted to avoid V-DOM diffing (because of the relative high expense of tree diffing) and just diff the dynamic data instead, but I haven’t thought of a good solution for how to render that data on the client.  It seems to me that caching all of the static content loses context which would mean you’d have to send the context (presumably in the form of duplicate templates) to the client at some point (probably first page load, maybe on websocket connection instead?)</p>
<p>Are there any clever ways to encode the minimal amount of context into the compile time generated functions such that you could only diff on the dynamic data rather than a tree diff or would you just end up tree diffing again?  I realize texas hasn’t been a target for you so feel free to ignore my questions that are very texas specific</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="101158" 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/71">Post #70</a>
	                </div>
	            </div>
              <div id="likers-container-101158" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="101158"
                     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 #70"></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=8">Load more posts (71 remaining)</a>
</div></template></turbo-stream>