Problem/Motivation
See #2499157: [meta] Auto-placeholdering.
If blocks were to use the #lazy_builder pattern, they could be automatically placeholderable:
- if they specify themselves they are uncacheable, then #2543332: Auto-placeholdering for #lazy_builder without bubbling will ensure they are automatically placeholdered. This applies — at the time of writing — to the breadcrumbs block, which effectively means every page is not cacheable by #2429617: Make D8 2x as fast: Dynamic Page Cache: context-dependent page caching (for *all* users!). Once this and #2543332 land, that will no longer be the case.
- if they bubble max-age=0 or high-cardinality cache contexts, then #2543334: Auto-placeholdering for #lazy_builder with bubbling of contexts and tags will ensure they are automatically placeholdered.
(The above means that blocks will de facto be the unit of placeholdering. Of course, other things that use #lazy_builders will also be individually placeholderable. But, for those things that don't use #lazy_builders, the block that they are rendered in will then automatically be placeholdered, and thus ensure great cacheability for the containing pages.)
Proposed resolution
Have BlockViewBuilder implement #lazy_builder; no block plugins need to be changed, because they are already being rendered lazily. This issue simply changes it from #pre_render to #lazy_builder.
Remaining tasks
Generally: Review. See #41 and #42 in particular.
User interface changes
None.
API changes
- Change:
hook_block_view_alter()can no longer be used to alter cache keys/contexts/tags/max-age. The newly addedhook_block_build_alter()needs to be used for that.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #50 | auto-placeholdering-block_lazy_builder-2543340-50.patch | 26.99 KB | wim leers |
Comments
Comment #1
wim leersNote: this will fail at least
BlockViewBuilderTest. I felt it was more important to show the key parts of the patch soon, than to post a perfect patch.Comment #3
wim leersThis should fix the 11 failures in
BlockViewBuilderTest.#lazy_builderno longer allows us to easily unset#theme, which means we cannot easily avoid the theme system executing just to simplify tests, therefore… as of this patch, we don't do that anymore.$build['#suffix'] = '<br>Goodbye!';test case, so I've changed it to$build['#attributes']['foo'] = 'bar';— we're still testing the same modifiability.getCacheContexts()method. If we really turn out to have a need for such an alter hook, we should add a separate alter hook.Comment #4
wim leersAnd apparently the help and statistics blocks also aren't placeholderable, because both carry state: they store data in properties in their respective classes in their
blockAccess()implementations.So this is quite an excellent way to detect stateful blocks.
This should be green.
Comment #5
yched commentedJust wondering : don't ESI and BigPipe differ on that regard though ? ESI rendering happens during a different request, but I thought BigPipe placeholders were rendered as part of the original request (just, delayed after we flush the initial HTML skeleton to the browser).
Also, yeah, not fully sure of when a block should use the NonLazyBuildableBlockPluginInterface marker interface. I thought "my output depends on this and that" was already supposed to be carried by the cache contexts ? but here we're adding another flag somewhere else ?
Comment #6
wim leersFixed the statistics block to not be stateful instead.
(It was written in that way because it used to be the case that to not render a block, you had to have the block's access result not grant access, even if the user actually had access. Because otherwise it'd always render the block.)
Comment #7
wim leers#5: Excellent points. You're right regarding ESI & BigPipe — that comment is a tad wrong. And agreed on the concern that cache contexts should already do this, but there's a difference here: these blocks carry state. And that is the real problem here: if a block is relying on
$this->something, that got set either in ablockAccess()method (like Help & Statistics), or that is injected because it is a very special block (the main content block has a->setMainContent()method that is necessary for the rendering system to be able to get the main content into the block without relying on state).So, I've been thinking that StatefulBlockPluginInterface would actually be a better name. Thoughts?
Comment #8
wim leersAlso fixed the Help block to not be stateful.
Comment #10
wim leers#5/@yched: Please look at the #6 & #8 interdiffs. I think they quite clearly demonstrate what the "problem" is with these blocks.
99% of core's blocks don't do this. So, I'd think that only in rare cases, you have to think about this.
Comment #11
wim leersOops, I was slightly too fast: forgot to update the Help block to no longer use that interface.
Attached is also an interdiff that shows all changes for #6 -> #11 (this comment). It is that diff that most clearly answers @yched's questions in #5.
Comment #14
fabianx commented#5:
We have to distinguish two cases, which BigPipe can handle:
a) A block that is just placeholder'ed for this request. We simply send it later. In that case we need to store the data to process, send max-age=0 to avoid someone caching it, then process it later. That works, because state is known. We just defer rendering some parts. Main property: Smart cache can't cache that. Only BigPipe can deal with such a dynamically cached block.
b) A block that is placeholdered always. In that case smart cache will cache it as #attached placeholders. So we will probably not execute the request, so any state of the blocks needs to be fixed.
---
To the patch itself:
I like StatefulBlockInterface best.
An interface works well for blocks.
For other things I think the best is to use:
#create_placeholder => FALSE,
in combination with the #lazy_builder.
As we don't really want two code paths, which means what would be most nicely if that was set by an alter() callback on the plugin or via a hook (see below).
Hm, yes maybe it really cannot be lazily build and this is not just about placeholdering, but just a side-effect that comes later.
Lets add an alter hook here:
hook_block_pre_view_alter();
or
hook_block_lazy_view_alter();
And I still think it would be best to give the plugin a chance to alter the blocks cache keys.
if ($this->plugin instanceof AlterableBlockPluginInterface) {
$this->plugin->alter($build);
}
This does not yet deal with blocks using context values that are injected, which need to be able to change the cache keys themselves. (we could opt those out of lazy building for now).
This is probably fast for all cases where smart cache is not involved, but we should measure that.
As we need to again load the things.
Also why use static methods here, we can have that be a controller callback.
Background:
We really should implement LazyBuilderPrepareInterface soon, so we can multi-load all entities in advance.
While for blocks that is not too huge a concern by adding #lazy_builder to entities it will.
So the help block would then always be visible right?
I think placeholdering the help block atm. while interesting should be a follow-up and making the block non lazy-buildable first.
Comment #15
wim leersFail caused by fixing the help block. Now the help block's
urlcache context bubbles always, like it should. Fixed test expectations.Also simplified
HelpBlockcode that I already touched slightly more: I was able to just delete it because it now was identical to the base implementation :)Comment #16
wim leers#14.1: renamed to
StatefulBlockPluginInterface.Comment #17
wim leers#14.4: I'd prefer to not implement any of those suggestions in this issue, because:
#14.5: We need to again load the block config entity, but that's statically cached already anyway. It uses a static method because
BlockViewBuilderis not a service, and you can only point to an object if it's also a service. Hence static method.#14.6: Yep, see #15 :)
Comment #18
wim leersFabian asked me to do the fixes for the Help & Statistics blocks in a separate issue, to keep this issue focused. Opened #2543554: Clean up Help & Statistics blocks for that (patch already posted!).
Comment #19
fabianx commented#17:
4. There are use cases to change the cache keys. Cache Contexts are only useful for state that comes from the outside, not for state that is injected in.
However that is only useful for context block plugins (as that is the only outside injected state) and that has poor support in core, so that is not a good reason.
But core itself does:
So I think it would be cleaner to move that to an ->alter() method instead of hard-coding into BlockPageVariant as contrib cannot and should not override the BlockViewBuilder just for that.
We already have an issue for that though and its a pure API addition, so not totally fixed on that as long as there is some way to alter it:
I am not sure we can do an API change to remove the ability to change #cache at all - as we also removed hook_page_alter(). So how can you change the cacheability of a block from an outside module then?
e.g. I know that this block is user cacheable in my configuration I want to bundle all of that in a mysite_performance module.
That is perfectly possible right now, but no longer after this patch.
So the MVP is to add another alter hook to keep the API / behavior change to a minimum.
14.5:
If that is not a service how will we be able to make that a LazyBuilderPreparableInterface service then? We really will need that as loading entities (and plugins) in bulk is way faster.
Comment #20
wim leersWhy is that not sufficient?
LazyBuilderPreparableInterface, but right now, it is hard to justify.Comment #21
fabianx commented#20.4: Because subclassing is not the right pattern here. I want to alter, not change. And I want to alter in whatever way I want. (... and and and msonnabaum promised me an alter hook :p.)
Also we are supposed to keep API changes to a minimum and removing an alterable thing is a way bigger API change then splitting it up in two alter hooks.
20.5:
Okay, that sounds good. Can we open an issue for that - if we don't have one already? Yes, pure API addition, just a performance improvement.
Comment #22
Crell commented"blocks that carry state" is a meaningless phrase to most developers. Blocks should never carry state, because they're more of a service than a value object.
What we're actually talking about here is blocks that call some method in the access() method, cache it to a property, and then check that property in the build() method. "Stateful block" is a useless description of that case, and I would have no idea what that even meant if I were not reading this issue.
This comment block is a bit better, and something like this is what belongs on the interface instead. However, "carry properties" isn't descriptive since all blocks have properties for things like configuration.
Recommended alternative, to be put on the interface docblock:
Generally, blocks should not have dependencies between their methods. For example, the build() method and access() method will not always be called, and not called in the same order, depending on how the block is being rendered. That allows Drupal to render blocks out-of-order for better performance and caching.
In rare cases, a block may have a good reason to ensure that its methods are called in a predictable order. Generally that is because data that is computed in the access() method is also used in the build() method, and is cached in a property for performance. Such blocks should implement this interface to signal to Drupal that they are not safe to call out-of-sequence.
----
And now that I think about it, what (good) reason is there for a block to even do that at all? If it's properly written, then both build() and access() would sub-call to the same method, and that method would generate the value if needed. That way if they're called independently of each other, the data still gets generated as needed. Or is the issue deeper than that?
Normally should use static, no?
static::, not self::, in pretty much any case I can think of. (self: here means a child class cannot ever override that method.)
Of course, then I would also ask WTH this is static and not a normal method. :-)
Insert obvious criticism here...
Then shouldn't MainContentBlockPlugin implement the Stateful interface, since that's the opt-out flag? If not, then it means Stateful is the wrong name for that interface if we can't use it consistently. :-)
Comment #23
wim leers#21.4:
#21.5: I wouldn't know how to word that issue; it's a proposal you made — that makes sense at a high level — but I think it'd be better if you create that issue. You'll want that issue anyway, regardless of this one, so :)
#22: many thanks for your review! It's much appreciated!
This is why I originally called it "NonLazyBuildable".
RE: your proposed alternative interface docblock: I didn't go with that, because the "out of sequence" part doesn't capture what the problem is. It really is about a block plugin instance that is carrying state. i.e. this line:
When that is called immediately (like we do for stateful block plugins in the current patch), then
$build['#block']is set to the entity that has the plugin instance that contains the state (e.g. the main content injected into the main content block plugin). But, if it is lazily built, then a new block plugin instance is created, which hence doesn't have the state.So, to make a first step to address your feedback (I'm sure we'll hash it out further in subsequent comments), I already moved the docs you liked better from
BlockViewBuildertoStatefulBlockPluginInterface.interface MainContentBlockPluginInterface extends StatefulBlockPluginInterface.Comment #24
wim leers#2543332: Auto-placeholdering for #lazy_builder without bubbling landed. And soft-blocker #2543554: Clean up Help & Statistics blocks landed also!
Lets' get this moving forward again? This has been blocked on reviews for almost a week now. (EDIT: by that I meant: gently nudging Fabianx & Crell :P — whose feedback I replied to in my previous comment and am waiting for their further thoughts so we can work towards consensus.)
Comment #25
dawehnerApparently a bad comment
I think non lazy has been worse, because its coupling the name to one specific concept of rendering rather than with stateful, which deals with generic state problems
So get_class() works the same as __CLASS_, but it doesn't take into account late binding, so we should better be able to deal with that. And well, for that case static::CLASS is exactly what you need, see http://3v4l.org/le0Di for an example about that.
You can use static::CLASS here as well, see http://3v4l.org/vlA9g
So why do we still need that escaping? Don't we have autoescaping now? Can we have a follow up for that? Please also add a todo
Please add the empty strings
This is not obvious, why it should be stateful
Do you mind adding a comment why? I mean its state depends on the exposed cache contexts which should be basically the entire of url for example
Comment #26
wim leersFirst, a straight reroll now that #2543554: Clean up Help & Statistics blocks has landed, because #23 still contained that. So this patch is now smaller again, like it originally was.
Comment #27
wim leersComment #28
dawehnerOH well, I was suggesting to use
t((string) $this->renderer->renderRoot($build));instead oft((string)$this->renderer->renderRoot($build));Comment #29
fabianx commentedFound not much, looks great!
Two main concerns:
- hook_block_build_alter() or hook_block_lazy_build_alter() is missing; use cases described below.
- FeedBlock is not taken care of. At least some manual testing would be nice.
One little concern:
- Needs some profiling so we don't regress here (much).
IIRC, we are still nit-picking on the name. I defer to Crell on that.
Can we somehow ensure that all blocks that use contexts from e.g. URL extend that class?
e.g. the FeedBlock?
I still want my alter hook here.
hook_block_build_alter().
Another reason is that its currently impossible to set:
#create_placeholder => TRUE,
which would be helpful.
While for blocks itself this still can be follow-up, it should be added a hook_block_build_alter() here to allow that.
That makes it possible to set 'auto-placeholdering' in stone and also turn it off for select blocks easily.
Did we measure how much impact that has?
e.g. some little profiling.
Especially when e.g. all visible blocks are somehow placeholdered.
Comment #30
wim leersWill do the profiling and add the alter hook.
Before doing so, can you clarify this:
I have no idea what you mean by that.
Comment #31
fabianx commented#30: There is one sole user of "contexts" in core. The Feed Block.
The Feed Block uses a configured context to select the feed to be shown, if I understood it correctly.
There also is some test coverage that tests contexts for blocks by providing I think a node block showing a node from the URL.
I want to avoid this breaking blocks-with-contexts, when a block-using-context is placeholdered.
I might be wrong and it all works, but lets at least manually test that it is the case.
And if it breaks it lets ensure those blocks use StatefulBlockInterface for now.
Comment #32
wim leersFrom
AggregatorFeedBlock:So this is not at all using contexts.
In fact, the only one that does AFAICT is
\Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock, which exists only for testing purposes. Given that, I'm not entirely sure what you want me to do.Comment #33
wim leersTim Plunkett pointed me to
\Drupal\block_test\Plugin\Block\TestContextAwareBlock, which is the one used in "contexts + blocks" tests.Comment #34
wim leersAnd he also pointed me to #2377757: Expose Block Context mapping in the UI, which makes the feed block use contexts indeed. I bet that's why you thought that was the case :)
Working on this next.
Comment #35
andypostincomplete comment
Comment #36
fabianx commentedTo be more clear:
I am neither expecting full support for blocks using context here, nor full coverage, etc. This patch is great as is and way within scope!
I just want to make sure that we either exclude those blocks by default or give an easy way to exclude. And especially that we keep those in mind.
Similar to how we used max-age=0 for some uncacheable things, then later worked on the cacheability in a follow-up.
I guess we need a new word: placeholderability :-p
Comment #37
wim leers#29.1: Blocked on Crell, added to remaining tasks in IS.
#29.2 + 36: postponing handling that to a next comment, until Fabian and I get a chance to chat so we can get on the same page
#29.3: Done. Also vastly expanded the test coverage: now tests not only cache keys and tags, but also contexts and max-age, plus all in combination (keys, contexts, tags, max-age), and also tests
#create_placeholder. Added API docs. Ensured the wording is consistent with the existing docs forhook_block_view_alter().#28, #29.4, #35: Up next.
Comment #38
wim leersd.o--
Comment #39
wim leers#28: done.
#35: done.
Comment #40
wim leers#29.4: done. In doing so, I discovered two small things that unnecessarily worsened performance:
\Drupal::service('module_handler')inBlockViewBuilder::viewMultiple()instead of injecting that service; fixedBlock::load($id)instead ofentity_load('block', $id)in the#lazy_buildercallback. (Block::load()required a fair bit of magic, and a single call to it resulted in ~70 additional function callsI profiled both with and without the breadcrumb block marked as cacheable, since #2483183: Make breadcrumb block cacheable is very close, at which point all blocks are cacheable and none are auto-placeholdered.
Note that the wall time is effectively meaningless, there's a lot of variance on there, it is essentially equivalent. In none of the cases, the I/O differs, memory usage is equivalent, so only number of function calls matter.
/contactbefore vs. after/contactbefore vs. after, with cacheable breadcrumb block/node/1before vs. after/node/1before vs. after, with cacheable breadcrumb blockComment #41
wim leersSo, this issue completely failed to address one part: Contexts, i.e. context-aware blocks. This is what @Fabianx was getting at in #29.2 & #36.
A. Discussion to find a better name for
StatefulBlockPluginInterfaceAnd while discussing #29.1 with Crell — i.e. determining the final name for what is currently called
StatefulBlockPluginInteface— that came up too. We were exploring the reasons why a block plugin would need to implement that interface, to find the best possible name. And when we got to the point where we said , we arrived at the natural conclusion/question: .That brought us back to #29.2, and is where we got stuck.
B. Context-aware blocks are a problem
The reason it was easy to forget about Contexts/context-aware blocks is simple: core has zero actual blocks that are context-aware. (There are a few test-only blocks, but those are only tested in non-rendering ways.) That's being fixed slowly in #2377757: Expose Block Context mapping in the UI + #2550199: Add a ContextProvider for Feeds.
The problem with Contexts/context-aware blocks are manifold:
— but then we'd of course also need a way to deserialize the serialized Context back into an actual Context.
(I can't answer points 1 and 2 myself because I can find neither documentation nor test coverage. I'm sure tests exist, but not in the form of integration tests for blocks.)
Conclusion: the Context system is not designed to run in isolation, because if it were, we'd be able to both capture a specific context and recreate it. Neither is currently supported.
This is why @Fabianx said this in #36:
C. Context-aware blocks are actually not a problem
… at least not in the SingleFlush and BigPipe render strategies. (SingleFlush is the render strategy that Drupal has used forever: build the entire HTML response and then send it when it's completely ready.)
Because when we replace placeholders in both SingleFlush and BigPipe render strategies, we are still operating within the actual/original request context. Which means that blocks will actually be able to access the Contexts they need.
For an ESI render strategy, however, this breaks down. Because with ESI, the rendering of the placeholder happens in an ESI request, not in the actual/original request. Which means Contexts won't be available.
Conclusion: in the current situation wrt Contexts + Blocks, we are explicitly relying on a leaky abstraction, on imperfect isolation. Because the context system is not designed to be able to run in isolation (see earlier). And, that's even fine for SingleFlush and BigPipe, because those only render blocks in the actual/original request context.
D. Context-aware blocks: able to render them in isolation when using ESI
We need two things to truly be able to render context-aware blocks in isolation:
routeorurl(orurl.*, e.g.url.query_args:foo), then the only way to render it in isolation is to do routing. Which means the ESI client needs to send the actual request URL to the origin, so that the origin (Drupal) can run routing. Drupal would get aX-Original-Request-Uriheader.This can be done in a follow-up.
Proposed next steps
(Issue title updated according to the proposed next steps.)
!empty($block->getPlugin()->getPluginDefinition()['context'])) => make it non-placeholderable by setting#create_placeholder => FALSE.#create_placeholder => FALSEif not all contexts can be serialized.Comment #42
wim leersThis comment and reroll are merely an unfortunate distraction. The next reroll will simplify the patch.
In a testing issue where I was trying something to simplify this patch further, I discovered that the last green patch (in #40) is no longer passing in HEAD. Specifically,
\Drupal\system\Tests\Form\RedirectTest::testRedirectFromErrorPages()is failing (that test was introduced by #2206909: Regression: Form submit redirects from 403/404 pages are no longer possible, >1.5 year ago).It's failing because it is testing that a form in a block (as opposed to a block in the main content area) is able to do a redirect on a 403/404 page (i.e. on a page where the kernel chooses what to render based on a kernel exception), and this patch automatically placeholders that block, which causes the redirect to occur later.
The root cause of the problem is that forms do redirects like this:
i.e. a pre-existing bit of nastiness in HEAD.
The reason it was passing in #40, is because #2551989: Move replacing of placeholders from HtmlRenderer to HtmlResponseAttachmentsProcessor got committed in the mean time, which causes blocks to be rendered later, during the kernels' RESPONSE event. Which means that when the
EnforcedResponseExceptionexception finishes bubbling, it does not trigger a kernel exception, because we're already in the response event.Whereas in #40/earlier HEAD, a nested kernel exception occurs (first a 403/404, then the
EnforcedResponseExceptionwithin the handling of that 403/404 exception).In other words, this small interdiff fixes a bug in #2551989: Move replacing of placeholders from HtmlRenderer to HtmlResponseAttachmentsProcessor, which only is an actual problem because Form API works in this crazy backward way :/
Attached is a reuploaded (identical, just rebased) #40 patch that is expected to fail, and a new patch with the fix (see interdiff).
Comment #44
wim leersAlright, the fail patch failed as expected, the other patch passed as expected. Great.
Now on to the next reroll, which will simplify this patch again.
Comment #45
wim leersSo, a key part that we got stuck on earlier, is the naming of this new
StatefulBlockPluginInterface. But, the only examples we have are the main content block, and the Views exposed filters block.We always thought the latter is directly dependent on "the main View" for the page (i.e. the one that's the main content, i.e. generated by the route's controller). But a closer look at
ViewsExposedFilterBlockmade me doubt that. So, I stepped through it. And, indeed, the Views exposed filters block in Drupal 8 no longer depends on the main content at all :) It has its own, non-executedViewExecutablethat is constructed independently. So, hurray! This is great!That means the only block with special needs is the main content block. And that block already is special.
Conclusion: we can remove
StatefulBlockPluginInterface! A whole layer of complexity is avoided. When the need arises in contrib, we can still add something like this, with more wisdom and experience based on those real-world examples that we encounter — if any.Patch & IS updated accordingly.
Comment #47
wim leers#45 contains a random fail. Easy fix.
Comment #48
wim leersSo, now that we have a simpler, green patch, we can focus on the remaining problem: context-aware blocks. See #41 for a full analysis.
First, I needed my understanding/analysis of context-aware blocks confirmed. Tim Plunkett confirmed in chat that:
contextannotation indeed lists all contexts it may ever use:!empty($block->getPlugin()->getPluginDefinition()['context'])?… so it can be done even more elegantly than I anticipated :)
context_mapping, then the block effectively is being rendered in full isolation.Conclusion: we can easily make sure that blocks which depend on contexts that aren't defined in
context_mappingwill get#create_placeholder = FALSEset, to prevent them from being rendered outside the main request.Comment #49
wim leersI forgot to set #47 to NR. Such noob.
Comment #50
wim leers(Before reading this comment, please read #41.)
hook_block_build_alter()set'#create_placeholder' => FALSE.hook_block_build_alter()implementations can set or override#create_placeholder(but currently it only tests theTRUEcase, for absolute peace of mind it should also test theFALSEcase; done in this reroll).Conclusion: this patch is ready; it doesn't need to do any further work to deal with Contexts/Context-aware blocks. Placeholdering of Context-aware blocks works fine for >99% of sites (no ESI), and for the remaining <1% (ESI) there is test coverage to ensure that the contrib ESI module can prevent Context-aware blocks from being placeholdered. The ability to serialize and unserialize Contexts is therefore only necessary for this <1% of sites, and can easily be an optional interface added in Drupal 8.x.0.
Let's explain why BigPipe is sufficient, and ESI is not a great fit for most sites anyway.
BigPipe will be sufficient for 99%, because ESI will only be actually useful on pretty advanced infrastructure setups: the setup must cache the ESI fragments in the ESI client (Varnish or something else), otherwise they'll end up bootstrapping Drupal for every ESI request. Not to mention that Varnish (and other, but not all) ESI clients in fact perform ESI requests serially, not in parallel. So your page that is cached in the ESI client and which just needs N blocks rendered in Drupal is then waiting for N Drupal bootstraps plus rendering, plus network overhead/latency.
That's the beauty of BigPipe: a single bootstrap, no network involved, no additional infrastructure required.
Comment #51
fabianx commented#50 Two little corrections:
a) ESI is planned for core in 8.1.x or 8.2.x (but not for 8.0.0).
b) There is still the possibility of using a middleware near page cache level to achieve an ESI like effect in core (essentially smart cache at a higher up level).
That all only works because smart cache is sitting after routing or rather it wraps the controller callback, which means that nothing can be happening in-between in comparison to a 'real' request.
That all said, the only reason for that exercise and excursion into 'blocks-with-contexts' land was to ensure that we don't break things for those cases. (not solve all the problems in here).
It seems we don't and the alter hook allows to easily set TRUE / FALSE the placeholder flag, so that is great.
Hmmmm.
While this makes a lot of sense for the test case, I think the better fix is to ensure forms-in-blocks are not placeholderable by implementing the alter hook.
On the other hand this will only become a problem with BigPipe and a very apparent problem then, so I think it is fine to leave here and to re-discuss #create_placeholder_options in the BigPipe issue, which should fail in the same test then.
Love it!
I already reviewed this several times and it looks ready to me now.
Setting RTBC, but also adding 'Needs profiling'.
Could we get some base performance numbers though - to see what the impact of the additional indirection is?
We for sure can gain 100% of that back, but it would still be good to know.
Comment #52
wim leersFor profiling, see #40. :)
Comment #53
fabianx commentedOhhh, I totally missed #40.
That is great and exactly what I wanted to see.
Fantastic that we even save some time on cache hits and good that the overhead is not that much worse for an auto-placeholdered block.
Comment #54
Crell commentedWow. WimLeers++!
Comment #55
catchHave looked through this a couple of times and it looks good, also discussed the issue a bit with Wim in irc.
Committed/pushed to 8.0.x, thanks!
Comment #57
wim leersYAY!
See you next in #2543334: Auto-placeholdering for #lazy_builder with bubbling of contexts and tags.