activeadmin / arbre

An Object Oriented DOM Tree in Ruby
MIT License
756 stars 74 forks source link

Use streaming responses #67

Open varyonic opened 6 years ago

varyonic commented 6 years ago

See activeadmin/activeadmin#2689

The unused in-memory DOM representation more than doubles the memory usage required to service a request and complicates the implementation to having a seperate buffer per element. I think a lot can be gained my dropping the in memory DOM representation: a single ActionView buffer can be passed from parent to child, lowering memory usage and allow us to use streaming responses.

joeldrapper commented 2 days ago

This is essentially how Phlex works and it’s really fast because you don’t need to allocate an object for each element. The generated HTML tag methods are essentially:

def h1(**)
  @buffer << "<h1" << build_attributes(**) << ">"
  yield
  @buffer << "</h1>"
end
varyonic commented 2 days ago

Yes, see https://github.com/varyonic/arbo/commit/312ee735b30be621ba26e22776fc2a55afccc2aa?diff=split&w=1 for my less elegant but working replacement of Element#to_s. I think it would be interesting to replace Arbre or Arbo with Phlex in ActiveAdmin but I am not familiar with how Phlex interoperates with ActionView and Rails helpers (especially form builders, though replacing Formtastic would also be good). Could it be done in a way that is (mostly) backward compatible or has a simple migration path?

joeldrapper commented 2 days ago

Could it be done in a way that is (mostly) backward compatible or has a simple migration path?

I expect so. Phlex Rails defines wrappers for each ActionView helper because it needs to behave in different ways depending on the kind of helper.

There are essentially two kinds of helpers:

  1. Value helpers return values that you typically output as text or attribute values. These helpers should work as normal in a Phlex context.
  2. Output helpers return HTML that should be pushed to the output buffer immediately.

For example, here the link_to helper is an output helper, and the dashboard_path helper is a value helper.

link_to(dashboard_path) { "Dashboard" }

We don’t need to do anything like

unsafe_raw(
  link_to(dashboard_path) { "Dashboard" }
)

All the helpers are defined here. https://github.com/phlex-ruby/phlex-rails/tree/main/lib/phlex/rails/helpers

Some helpers such as form builder helpers need some extra managing to maintain compatibility. Helpers like form_with yield a FormBuilder, which has output helpers and value helpers on it, so Phlex decorates the form builder.