Return htmx responses as SimplePageVariant

Created on 4 May 2025, 8 days ago

Problem/Motivation

When we request content using HTMX it is the main content that we want to receive. We don't want or need all the surrounding blocks that Drupal generates.

Proposed resolution

When a request comes from HTMX, set the page variant to SimplePageVariant.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

πŸ“Œ Task
Status

Active

Version

11.0 πŸ”₯

Component

request processing system

Created by

πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @fathershawn
  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York
  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York
  • Merge request !12032Resolve #3522597 "Simple htmx responses" β†’ (Open) created by fathershawn
  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    Opened an MR that uses a default simple page with a header control for using a block page variant.

  • Pipeline finished with Failed
    8 days ago
    Total: 219s
    #488469
  • Pipeline finished with Failed
    8 days ago
    Total: 162s
    #488470
  • Pipeline finished with Failed
    8 days ago
    #488472
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    Can we make use of a main content renderer like we do for dialogs?

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    Maybe. That doesn't necessarily look simpler to me but I don't know the internals as well as @larowlan. The work in πŸ“Œ Process attachments (CSS/JS) for HTMX responses and add drupal asset libraries Active is based on returning an HtmlResponse object, so would we be creating a simpler version of \Drupal\Core\Render\MainContent\HtmlRenderer? I would think we would still need an event subscriber to divert the request to the alternate renderer.

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    Another advantage of the page variants is that SimplePageVariant contains system messages as well as main content. That would allow the calling element to use hx-select-oob, or for us to add an hx-swap-oob to the response, and display error messages as well as the selected content from the response.

  • Pipeline finished with Failed
    5 days ago
    Total: 162s
    #491290
  • Pipeline finished with Failed
    5 days ago
    Total: 386s
    #491297
  • Pipeline finished with Failed
    5 days ago
    Total: 264s
    #491330
  • Pipeline finished with Success
    5 days ago
    Total: 653s
    #491375
  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    All tests green, including new unit test for this subscriber

  • πŸ‡¬πŸ‡§United Kingdom catch

    System messages in the AJAX system are rendered via MessageCommand, and the same infrastructure is used by BigPipe since πŸ“Œ Use MessagesCommand in BigPipe to remove special casing of the messages placeholder Fixed . I'm not sure how that would compare to #8 in terms of final implementation, although presumably we might need to support an HTMX version of MessageCommand for bc anyway?

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    For the idea in #6 we would need HTMX to send ?_wrapper_format=htmx in the query string of all requests. This looks like it is doable via the htmx:configRequest event. Then, we add a service similar to HtmlRenderer but which can do less work - it wouldn't need to care about display variants at all.

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    Rendering the system messages in the response would mean that we wouldn't need a command to define the messages. The core systems of defining and displaying messages is available.

    We would need to implement in a later issue either

    1. Always select and display system messages as additional inserted content
    2. Provide an operation for selecting the messages from the response and displaying them to be used with appropriate
  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    @longwave Okay, that's two experienced maintainers recommending a renderer over page variants. Thanks for weighing in!

    We don't need the query string as HTMX adds the header HX-Request: true to all requests. I'll start to work on that approach as an alternative. I think we do still want title though so that the HTMX feature of swapping the title is available if appropriate but we turn it off by default.

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    We do need the query string, as that's how MainContentViewSubscriber decides which instance of MainContentRendererInterface is needed to render the page; without the query string it will fall back to HtmlRenderer.

  • πŸ‡«πŸ‡·France andypost

    +1 to #14 it will use seriously less code selecting renderer earlier

    btw about messages ...hope it covered with drupal.message since 8.7 β†’

  • πŸ‡«πŸ‡·France andypost

    btw that's exactly a place to extend because attachments also should be delivered and merged, and not sure about "ajax_page_state"

  • πŸ‡«πŸ‡·France andypost

    and maybe a middlegroud is to add middleware to append query string when header provided

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    RE: #16 - yes we have that covered in πŸ“Œ Process attachments (CSS/JS) for HTMX responses and add drupal asset libraries Active

  • πŸ‡¬πŸ‡§United Kingdom catch

    Unsure how this interacts with caching as well - if the same route is usable via both standard HTTP and HTMX then we want the cached responses to differ.

    If it's a GET request (which it should be for HTMX when possible), then the internal page cache won't differentiate so it could get corrupted, and same problem with varnish/CDNs, so we would have to enforce that the HTMX route is only used for HTMX and throw a bad request exception or something when the header is missing.

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    That makes me think we should just set the query string on the client side, even if we also have the header set.

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    #19 reminded me of πŸ› Enable header-based proactive content negotiation with optimizations and opt-outs available. Needs work where Drupal does not use the Accept header for format negotiation, primarily because of external caching issues.

  • πŸ‡¬πŸ‡§United Kingdom catch

    #2364011: [meta] External caches mix up response formats on URLs where content negotiation is in use β†’ was I think the definitive issue for Drupal 8 where accept negotiation got canned. I haven't re-read that issue recently but remember the whole area being extremely painful at the time. So yes, on the basis we would want at least some HTMX responses to be cacheable in edge caches, let's use a query string from the client.

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    I'm so glad to be working with collaborators who have a historical perspective on the code! This is an enhancement not a requirement that will give a bit of performance boost. I'm going to postpone it and move it down the task list before BigPipe.

    In the module, this simplified HTML response is a route option and scanning the linked history that may be a good thing. Let's think about routes we might build to serve requests from HTMX and pick up this work in a while. Ideas that I have for routes are:

    • the one I have in the module /htmx/{entityType}/{entity}/{viewMode}
    • one to render placeholders as the main content
  • πŸ‡¬πŸ‡§United Kingdom catch

    I don't think the routing concern is necessarily a big pipe conversion blocker. Big pipe just uses render placeholders that return an AjaxResponse object, there's no routing involved.

  • πŸ‡ΊπŸ‡ΈUnited States fathershawn New York

    It might not be, but if we refactor BigPipe to use HTMX we should return HTML - probably with the placeholder as the main content, and I wondered if that might intersect with this use case??

Production build 0.71.5 2024