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
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 11 to 20- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
tmbb
Yeah, sending
,"... segment ..."is slightly less data thanindex:"... segment ...". That’s what I meant. And for a flat array I can have even more effucient encodings.tmbb
This is amazing. I can’t believe I’ve missed this optimization! This is probably bigger than my inline stuff. It requires a slightly smarter Javascript client, of course, but it’s a great idea.
And one I can implement in Vampyre, too.
tmbb
Are you sure you eant to apply this optimization on regular rendering? This makes the initial render dependent on Javascript, which I’m not sure is a good idea.
josevalim
I wanted to say the first rendering for the JS client. Good catch.
tmbb
@josevalim, do you already have a strategy to optimize
form_for/4without turning it into a macro? I’m extremely curious about what you’ll come up withjosevalim
We will go with the simplest approach for now which is to convert this:
into this:
Effectively removing the nesting. Not the prettiest thing but definitely the simplest that works.
tmbb
Hm… I don’t see how this can work. How is it possible that
fis simultaneously a%Phoenix.HTML.Form{}struct and a binary containing the opening<form>tag, the CSRF token and the other hidden input tags that forms in Phoenix have?tmbb
You’d have to define something like:
which I actually prefer instead of your version above.
On further thought, I wonder if optimizing forms is such a big deal. With the lack on inlining, it’s possible that you don’t gain much if you’re not inlining segments (which Vampyre can do but LiveEEx can’t - at least not yet). After all, forms in phoenix depend a lot on HTML generating functions. For example, let’s look at an example of a form generated by a Phoenix generator:
The only static segments inside the form are sequences of whitespaces,
<div>and</div>at the end. Also, almost all of the dynamic segments depend indirectly on the changeset. And onf, of course. LiveEEx doesn’t have a way of determining which fields to update whenf(or@changeset) changes, so it will have to regenerate all widgets which depend onf, which are all of them.You will also have to regenerate the CSRF token, unless you mark that as static somehow, as well as the other hidden input tags.
If you’re going to have to generate almost the whole form, maybe it’s not worth it to optimize that part.
On the other hand, in Vampyre I can optimize most almost all input fields to mostly static data with just 3 dynamic segments, with most of it being static.
And the
form.namesegments can be optimized into static segments if we assume that the form shape won’t change (which is pretty much true for almost all forms).PS: I’ve just noticed on reviewing my code that my
form_formacro doesn’t support setting thevalueattribute yet, but supporting it is a very minor change.josevalim
We just need to implement Phoenix.HTML.Safe for it.
It is most likely that actual user forms are more complex than this. It also serves as a good example on how to handle nesting and it opens up the possibility to explore other approaches later.
I think if there is a lesson in this whole discussion is that starting simple allows us to incrementally improve based on new ideas, feedback, etc. If I had started thinking about how to optimize comprehensions, we may have ended-up with a more complex solution and very different than the one today. I am happy to go with baby steps.
tmbb
Well, it goes both ways xD If I had started thinking about how to optimize for comprehensions (instead of quitting), I’d have stumbled upon your solution about 1 month ago
It’s a natural consequence of trying to do things at compile time, because we can take advantage of the fact that
foris a special form that can’t be overriden, so it can be analyzed statically.But I believe we may have started with different priorities.
You had @chrismccord’s example from the LiveView talk and and maybe optimizing such dynamic highly dynamic templates was a priority for you.
I started thinking about (mostly static) forms and how to optimize those, because those are the ones I saw myself using the most, especially the part of having real-time form validation without writing any JS. That brought me naturally close to the idea of inlining static parts and merging adjacent binaries together. Yes, live tables that could update in response to typing in a search field were cool, but I had already given up on those
I’m the first to praise the simplicity of your implementation but I think most of the complexity with my approach is unavoidable. It’s the result of implementing an optimizing compiler (although a very simple one) that tries to separate the static and dynamic parts in a very obsessive way.
The other main source of complexity with my approach is probably the attempt to maintain backward compatibility with Phoenix.HTML, which contains some things that are not very easy to optimize statically. The
tag()function, in particular, is a bit weird, and I should probably break compatibility so that it can be abetter building block for the rest. If I can encapsulate most of the complexity inside thetag()macro (because I need it to be a macro), thins will probably be much simpler in the rest of the code base.I don’t consider this “premature” optimization, because it’s essential for my main goal, which is to send the absolute minimum amount of data over the network for things like forms.