Use MessagesCommand in BigPipe to remove special casing of the messages placeholder

Created on 8 August 2023, over 1 year ago
Updated 25 June 2024, 6 months ago

Problem/Motivation

Discovered in πŸ“Œ Add PHP Fibers support to BigPipe RTBC .

When BigPipe was added to core, we didn't have MessagesCommand in core, see this comment:

 // The 'status messages' placeholder needs to be special cased, because it
    // depends on global state that can be modified when other placeholders are
    // being rendered: any code can add messages to render.
    // This violates the principle that each lazy builder must be able to render
    // itself in isolation, and therefore in any order. However, we cannot
    // change the way \Drupal\Core\Messenger\MessengerInterface::addMessage()
    // works in the Drupal 8 cycle. So we have to accommodate its special needs.
    // Allowing placeholders to be rendered in a particular order (in this case:
    // last) would violate this isolation principle. Thus a monopoly is granted
    // to this one special case, with this hard-coded solution.
    // @see \Drupal\Core\Render\Element\StatusMessages
    // @see \Drupal\Core\Render\Renderer::replacePlaceholders()
    // @see https://www.drupal.org/node/2712935#comment-11368923

It's not the Drupal 8.0.x release cycle any more! MessagesCommand was added in 8.8 https://www.drupal.org/node/3086403 β†’

Steps to reproduce

Proposed resolution

After rendering a placeholder in BigPipe::renderPlaceholders(), use Messenger::deleteAll() to collect whatever messages are in session, then add them to the ajax response in a MessageCommand.

If we only do this, then hopefully the tests will continue to pass (there's extensive test coverage of the current logic), or will at least pass with minimal tweaks.

Then if that bit works, we can remove all the logic that keeps messages last in the placeholder stack, since it shouldn't matter when that placeholder gets replaced - we'll be using the AJAX system to add the messages as they come in, instead of relying on collecting $_SESSION at the end of the request to replace them all at once. This will then require some reworking of the tests.

This should have two advantages:

1. It'll simplify BigPipe module.

2. Messages will appear as soon as they're available on big pipe responses, instead of all being added at the end of the request. While it's uncommon for placeholders to set a message, this could end up improving largest contentful paint when the messages area is the largest item above the fold. If there's already a message ready to be displayed at the beginning of the request, it will still be rendered as part of the placeholder (i.e. not via MessagesCommand), with the difference that the messages placeholder will be rendered in order instead of last.

Because the messages placeholder is usually in the view port, this should help at least a little bit with with cumulative layout shift and largest contentful paint for responses with messages to display.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

πŸ“Œ Task
Status

Fixed

Version

11.0 πŸ”₯

Component
BigPipeΒ  β†’

Last updated 17 days ago

Created by

πŸ‡¬πŸ‡§United Kingdom catch

Live updates comments and jobs are added and updated live.
  • Performance

    It affects performance. It is often combined with the Needs profiling tag.

  • Usability

    Makes Drupal easier to use. Preferred over UX, D7UX, etc.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @catch
  • πŸ‡¬πŸ‡§United Kingdom catch
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Messages will appear as soon as they're available on big pipe responses, instead of all being added at the end of the request.

    🀯

    I had not even thought of that! Tempts me to tag this too πŸ€“

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • Status changed to Needs review over 1 year ago
  • last update over 1 year ago
    Custom Commands Failed
  • πŸ‡¬πŸ‡§United Kingdom catch

    It works - not completely transparent but it's fine. Because the messages are added via the AJAX system, the resulting markup is slightly different, but it's just a small behaviour change, because we're changing the behaviour, not a regression.

    BigPipeRegressionTest now passes for me locally.

    BigPipeTest will fail because it's asserting hard-coded placeholder content, that'll need updating, but stopping for now so uploading what I've got.

    @todos for next steps:

    1. Fix the assertions in BigPipeTest to work with the new placeholder output.
    2. Remove the special casing of the messages placeholder from everywhere + inject the message service into BigPipe.
    3. Remove the test coverage for the special casing of the messages placeholder (but not all the other message tests!).

    Also all the above is going to massively conflict with πŸ“Œ Add PHP Fibers support to BigPipe RTBC (which might be nearly RTBC?!?!), so not in a huge hurry.

  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    That's AWESOME news! πŸ˜„

  • last update over 1 year ago
    29,949 pass, 2 fail
  • last update over 1 year ago
    29,949 pass, 2 fail
  • πŸ‡¬πŸ‡§United Kingdom catch

    OK OK CCF failures I was in a hurry :(

  • Status changed to Needs work over 1 year ago
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    This may also fix whatever is going on in πŸ’¬ Status messages block not showing while BigPipe module enabled in contrib/custom admin theme Postponed: needs info .

  • Merge request !6576Convert the patch to an MR. β†’ (Open) created by catch
  • Pipeline finished with Failed
    10 months ago
    Total: 516s
    #93881
  • πŸ‡¬πŸ‡§United Kingdom catch

    OK i went to the trouble of getting green tests first while the messages placeholder was still special-cased. This required adjusting some of the placeholder test cases since messages moved to a the AJAX command.

    Then I removed the special casing and the tests failed again - because with the messages placeholder rendered first, it directly shows the messages again, not via the AJAX command - which is expected behaviour if there are messages ready to show when the messages placeholder itself is rendered.

    So that was a bit two steps forward one step back, but the end result is the functional js tests include the AJAX command output and the functional tests include messages rendered by the placeholder, and we only have very minimal changes to the test coverage overall. Could have saved some work, but the end result is good I think.

    Still need to inject the messaging service but that's the last change I know of - trying to do this incrementally, even though it's a big simplification, it's removing complex logic and assumptions so could have gone wrong.

  • Status changed to Needs review 10 months ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    Ready for review now.

  • πŸ‡¬πŸ‡§United Kingdom catch
  • πŸ‡¬πŸ‡§United Kingdom catch
  • Status changed to Needs work 10 months ago
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    This looks amazing! Simpler, better performance, better usability too! 🀩

    Just one nit and one question.

  • Pipeline finished with Success
    10 months ago
    Total: 461s
    #94993
  • Status changed to RTBC 10 months ago
  • πŸ‡§πŸ‡ͺBelgium wim leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Beautiful.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    Discussed with @catch.

    There's one small interesting behaviour change. The new way of immediately adding messages via ajax means that you're more likely to get duplicate messages on the screen because you don't benefit from automatic deduping by the messaging system. If this turns out to be a big issue we can look to do the deduping in the messages AJAX.

    Also it is very odd that the markup is different - but themes already have to cope with this so it is not new.

    Given the benefits going to commit to 11.x and 10.3.x.

    We considered a change record for the above behaviour changes but decided that it would be noise as there is nothing obviously actionable or an easy way to see if you will be affected.

  • Status changed to Fixed 10 months ago
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    Committed and pushed 44c345dd9b to 11.x and 2172d1009c to 10.3.x. Thanks!

    • alexpott β†’ committed 2172d100 on 10.3.x
      Issue #3379885 by catch, Wim Leers: Use MessagesCommand in BigPipe to...
    • alexpott β†’ committed 44c345dd on 11.x
      Issue #3379885 by catch, Wim Leers: Use MessagesCommand in BigPipe to...
  • πŸ‡¬πŸ‡§United Kingdom catch

    The new way of immediately adding messages via ajax means that you're more likely to get duplicate messages on the screen because you don't benefit from automatic deduping by the messaging system.

    Just to say a caveat to this is that if you submit a form, the messages are added to session, and the next page renders them (the most likely way to get lots of duplicate messages), then the deduping logic will still kick in, because any messages in session are still rendered via PHP with the placeholder, not via AJAX. So this would only happen when messages are rendered after the messages placeholder itself is rendered (i.e. from another placeholder).

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024