tmbb

tmbb

@josevalim has published this video, where he livecodes some improvemens to EEx templates based on ideas from PhoenixUndeadView/Vampyre: Twitch

It was very interesting to see @josevalim going more or less down the same paths while solving a problem similar to my own with my Vampyre/PhoenixUndeadView project.

It’s amazing the way he managed to live code all of that without any preparation. My own solution to more or less the same problem is clearly over-engineered when compared to @josevalim’s solution, but it solves a different problem with different requirements, so it can’t be directly compared. My implementation also took much longer and is not as elegant (again, different requirements, so they can’t be directly compared).

I guess the main take-away from @josevalim’s video is that one can be very naïve when naming the variables, because variables nested deeper into the template will not overwrite the ones outside. I believe I had proved that to myself, but I still wanted unique names, so I went ahead anyway… I still think there is some value in having unique variable names (it makes it easier to inspect the compiled output), but seeing how much simpler it is to implement it the way @josevalim did it, I guess I think it’s not worth it to do it like I did.

The main difference between the new EEx improvements and Vampyre (and the reason why you can’t compare both probjects) is that EEx doesn’t attempt to expand macros and optimize the result (it wouldn’t even make sense in the case of such a generic project as EEx). It might make sense in a more specialized engine, like Vampyre, or the engine in Phoenix.HTML, where one expects a library of widgets to be available. That way, optimizing those widgets as much as possible makes sense.

From now on, I and @josevalim will probably pursue further optimizations in different directions, as explained on this github issue.

I’m still betting on using macros to do as much work as possible at compile-time and generate templates which are as optimized as possible, and regenerate all the dynamic parts each time the template is rendered. That is not as bad as it sounds, as I’ve managed to make the dynamic parts as minimal as possible and to make my templates as flat as possible.

On the other hand, @josevalim is now thinking about optimizing the templates by building a dependency graph on the template assigns, so that it’s possible to optimize only those segment that depend on the data that has changed.

Anyway, this was an amazing video

Most Liked

josevalim

josevalim

Creator of Elixir

Thanks @tmbb for the compliments and all of the ideas so far. The changes I did in EEx are indeed a small subset of what we would find in Vampyre or LiveView.

Today I live streamed the implementation of LiveEEx: https://github.com/josevalim/live_eex

The engine does two main things:

  • It keeps static and dynamic parts apart
  • It tracks when each assign is used and it does not compute such parts if the assigns did not change

The analyze code is relatively straight-forward and all it does is to track whenever an assign is used. However, in order to not change the semantics of the code, we give up the analyze if it sees any variable or lexical command.

This is a different set of optimization compared to Vampyre. Vampyre is about increasing the amount of static parts. Currently I am working on reducing when the dynamic parts are sent. Both are very useful.

Tomorrow we should work on template fingerprinting so we can handle nesting and we will likely work on the Phoenix integration. The whole thing should be less than 400LOC, which is really neat, and this would not be possible if it was not for your initial suggestions on how to structure compiled code! :slight_smile:

13
Post #1
josevalim

josevalim

Creator of Elixir

I just went ahead and implemented fingerprinting now. Here are the docs on why we need it.

I have also improved the analysis code to be more optimal and it is around 110LOC. There is a big comment section explaining how it all works: https://github.com/josevalim/live_eex/blob/3b4a8b727d577d8885f8816ef9adb3d244cb6acf/lib/engine.ex#L399-L511

With the analysis improvements, everything is on 440 LOC, slightly more than I expected but also doing more than I expected, which is quite good for everything it does. :slight_smile: The test suite is also really good, so I recommend checking that for any questions.

josevalim

josevalim

Creator of Elixir

I have also added support to for-comprehensions to live_eex, which drastically reduces the amount of data sent in for comprehensions, even on regular rendering. Take for example Phoenix’s scaffolded HTML page for index:

<%= for user <- @users do %>
  <tr>
    <td><%= field1 %></td>
    <td><%= field2 %></td>
    <td><%= field3 %></td>
    <td><%= field4 %></td>
    <td><%= link "Show", to: ... %></td>
    <td><%= link "Edit", to: ... %></td>
    <td><%= link "Delete", to: ... %></td>
  </tr>
<% end %>

If you have 10 users, the example above would send the static parts (the tr and td) for each user. Now we just send the static parts once regardless of the number of users. And if you are adding or removing users, the static parts are never sent again. This reduces the data of each initial render and of each update alike.

After all of those optimizations, the rainbow example that Chris showed at ElixirConf is now sending only 1% of the data that it did at the time. Back then it already rendered at 60 fps and reducing the amount of data sent is definitely going to make it more resilient to latency.

Last Post!

tmbb

tmbb OP

Yes, you are there. Vampyre is not there by design. I’ve made the conscious choice of avoiding that optimization for the time being. Sorry if I wasn’t clear.

EDIT: this is a criticism of Vampyre, not a criticism of LiveView

Where Next? Top

Trending in Discussions Top

cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
jtormey
Lately I’ve been thinking about how to organize components as a LiveView application grows. One of the pain points I’ve found (for myself...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews