Skip to content

Comments

Add OutputBuffer#raw and #capture to reduce the need to swap the buffer#45731

Merged
byroot merged 1 commit intorails:mainfrom
Shopify:action-view-buffer-slice
Aug 3, 2022
Merged

Add OutputBuffer#raw and #capture to reduce the need to swap the buffer#45731
byroot merged 1 commit intorails:mainfrom
Shopify:action-view-buffer-slice

Conversation

@casperisfine
Copy link
Contributor

Right now many helpers have to deal with two modes of operation to capture view output.

The main one is to swap the @output_buffer variable with a new buffer. But since some view implementations such as builder keep a reference on the buffer they were initialized with, this doesn't always work.

So additionally, the various capturing helpers also record the buffer length prior to executing the block, and then slice! the buffer back to its original size.

This is wasteful and make the code rather unclear.

Now that OutputBuffer is a delegator, I'd like to refactor all this so that:

  • @output_buffer is no longer re-assigned
  • A single OutputBuffer instance is used for the entire response rendering
  • Instead capturing is done through OutputBuffer#capture

Once the above is achieved, it should allow us to enabled Erubi's :chain_appends option and get some reduced template size and some performance.

Not re-assigning @output_buffer will also allow template to access the local variable instead of an instance variable, which is cheaper.

But more importantly, that should make the code easier to understand and easier to be compatible with StreamingBuffer.

NB: This will need a followup or two to remove the remaining @output_buffer re-assignments.

FYI @jhawthorn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any legit reason for using SafeBuffer as @output_buffer and its holding us back.

@casperisfine casperisfine force-pushed the action-view-buffer-slice branch from 665c9d8 to 60792cc Compare August 2, 2022 11:15
casperisfine pushed a commit to casperisfine/temple that referenced this pull request Aug 2, 2022
In rails/rails#45614 I modified
`ActionView::OutputBuffer` to no longer be a subclass of
`ActiveSupport::SafeBuffer` and as such it's not recommended
to use `SafeBuffer` for buffering views anymore.

Additionally in rails/rails#45731
I start doing some changes so that we stop mutating `@output_buffer`.
So template should no longer assign `@output_buffer` themselves.
casperisfine pushed a commit to casperisfine/temple that referenced this pull request Aug 2, 2022
In rails/rails#45614 I modified
`ActionView::OutputBuffer` to no longer be a subclass of
`ActiveSupport::SafeBuffer` and as such it's not recommended
to use `SafeBuffer` for buffering views anymore.

Additionally in rails/rails#45731
I start doing some changes so that we stop mutating `@output_buffer`.
So template should no longer assign `@output_buffer` themselves.
@casperisfine casperisfine force-pushed the action-view-buffer-slice branch from 60792cc to 4a75b85 Compare August 2, 2022 13:14
@jhawthorn
Copy link
Member

also cc @BlakeWilliams who has looked at output buffer swapping

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

casperisfine pushed a commit to Shopify/rails that referenced this pull request Aug 3, 2022
It's really not what it's meant for. `@renderer` is a better use
for this as it's the variable used by the DOM testing helpers.

Ref: rails#45731
Right now many helpers have to deal with two modes of operation to
capture view output.

The main one is to swap the `@output_buffer` variable with a new buffer.
But since some view implementations such as `builder` keep a reference
on the buffer they were initialized with, this doesn't always work.

So additionally, the various capturing helpers also record the buffer
length prior to executing the block, and then `slice!` the buffer back
to its original size.

This is wasteful and make the code rather unclear.

Now that `OutputBuffer` is a delegator, I'd like to refactor all this
so that:

  - @output_buffer is no longer re-assigned
  - A single OutputBuffer instance is used for the entire response rendering
  - Instead capturing is done through `OutputBuffer#capture`

Once the above is achieved, it should allow us to enabled Erubi's
`:chain_appends` option and get some reduced template size and some
performance.

Not re-assigning `@output_buffer` will also allow template to access
the local variable instead of an instance variable, which is cheaper.

But more importantly, that should make the code easier to understand
and easier to be compatible with `StreamingBuffer`.
@casperisfine casperisfine force-pushed the action-view-buffer-slice branch from 4a75b85 to fc0db35 Compare August 3, 2022 10:56
@byroot byroot merged commit 206b2b8 into rails:main Aug 3, 2022
judofyr pushed a commit to judofyr/temple that referenced this pull request Aug 7, 2022
In rails/rails#45614 I modified
`ActionView::OutputBuffer` to no longer be a subclass of
`ActiveSupport::SafeBuffer` and as such it's not recommended
to use `SafeBuffer` for buffering views anymore.

Additionally in rails/rails#45731
I start doing some changes so that we stop mutating `@output_buffer`.
So template should no longer assign `@output_buffer` themselves.
skipkayhil pushed a commit to skipkayhil/rails that referenced this pull request Jan 19, 2023
It's really not what it's meant for. `@renderer` is a better use
for this as it's the variable used by the DOM testing helpers.

Ref: rails#45731
camertron added a commit to camertron/rails that referenced this pull request Jan 30, 2023
A recent change designed to avoid swapping references to the view context's
output buffer (rails#45731) added a #capture
method to the OutputBuffer class. The original CaptureHelper#capture method
however still swaps the buffer via CaptureHelper#with_output_buffer, meaning
the @output_buffer reference is still reassigned by form helpers, etc. This
change delegates capture behavior to @output_buffer so a single buffer is
used per request.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants