Problem/Motivation

I noticed a regression in the 11.x branch between 11.2 and 11.3: If a placeholder is in a noscript tag, the bigpipe javascript (and htmx) will throw an uncaught TypeError.

Steps to reproduce

On the 11.x branch, enable BigPipe module, and in a custom module, add a placeholder to a noscript tag. For example,

$page_bottom['my_noscript_tag'] = [
  '#type' => 'html_tag',
  '#tag' => 'noscript',
  'child' => [
    '#create_placeholder' => TRUE,
    '#lazy_builder' => [MyTrustedCallback::class . '::getImage', []],
  ],
];

[Note, For easier debugging, I am using htmx.js rather than htmx.min.js]

When loading the page with a logged-in user, Firefox (or Chromium) will throw

Uncaught (in promise) TypeError: can't access property "dispatchEvent", elt is null

with stack trace:

triggerEvent /core/assets/vendor/htmx/htmx.js?v=2.0.4:3043
    insert /core/modules/big_pipe/js/big_pipe.commands.js?v=11.3-dev:60
    commandExecutionQueue /core/modules/big_pipe/js/big_pipe.commands.js?v=11.3-dev:31
    (Async: promise callback)
    commandExecutionQueue /core/modules/big_pipe/js/big_pipe.commands.js?v=11.3-dev:24
    reduce self-hosted:217
    commandExecutionQueue /core/modules/big_pipe/js/big_pipe.commands.js?v=11.3-dev:21
    processReplacement /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:69
    checkMutationAndProcess /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:94
    forEach self-hosted:157
    processMutations /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:118
    forEach self-hosted:157
    processMutations /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:117
    (Async: MutationCallback)
    <anonymous> /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:134
    <anonymous> /core/modules/big_pipe/js/big_pipe.js?v=11.3-dev:166

Proposed resolution

In this case, in Drupal 11.2 and earlier, bigpipe did not throw an error.

For obvious reasons we do not require that javascript replaces a placeholder in a noscript tag. We only need it to be replaced - by other means - when javascript is disabled.

So, in cases where the element can't be found and target === null, I would say bigpipe could simply stop processing this placeholder?

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3550388

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mfb created an issue. See original summary.

mfb’s picture

Status: Active » Needs review
catch’s picture

I think this would mean that no other placeholder strategy would find the placeholder either.

Wondering if bigpipe's placeholder creation should try to special case no script placeholders somehow.

mfb’s picture

Issue summary: View changes
mfb’s picture

I think this would mean that no other placeholder strategy would find the placeholder either.

Not sure what you mean by this - the non-javascript placeholdering has always worked fine - the placeholders are replaced on server side.

I did find a work-around I could use on Drupal 11.3 and later: I can instead have the noscript tag be part of the replacement markup, instead of wrapping the placeholder. Then, of course the javascript can find the placeholder, because it's not in a noscript tag.

However, rather than having to work around the issue, I think it would be best to avoid throwing here - just don't try to process the target if it can't be found.

mfb’s picture

Markup in a noscript tag is by definition already special-cased, because it's not interpreted as being part of the dom. And since it's only relevant when javascript is disabled, handling replacement on server side is fine.

I don't think there anything special that bigpipe should do, except just not error in any rare cases where the target can't be found.

mfb’s picture

Actually I realized my attempted work-around I mentioned in #6 doesn't work, because the noscript tag is added to the dom, and whatever is inside actually loads. So, I think my MR is the best solution: bigpipe javascript should just ignore any situation where target is null.

catch’s picture

Not sure what you mean by this - the non-javascript placeholdering has always worked fine - the placeholders are replaced on server side.

...

I think it would be best to avoid throwing here - just don't try to process the target if it can't be found.

What I mean is - I would assume that if something has already been replaced server side, then it would not be sent to the browser, so would not be a target at all.

mfb’s picture

I would assume that if something has already been replaced server side, then it would not be sent to the browser, so would not be a target at all.

Yes that would be correct. The exception is only thrown in the browser when it was not done server side.

There is no way to tell big pipe "only do this replacement server side because it's in a noscript tag", but such complexity isn't needed. We can just keep things working like they did historically: don't throw if the browser can't find a placeholder.

catch’s picture

@mfb ah OK - but doesn't that mean nothing would replace that placeholder then?

mfb’s picture

I just double-checked this and there is no change between 11.2 and the 11.x branch except that the TypeError is thrown. BigPipe JS also can't find a placeholder in a <noscript> tag in 11.2 - I had never actually noticed this fact before, since it wasn't a problem.. :)

nod_’s picture

Status: Needs review » Reviewed & tested by the community

Tried it out and that is the appropriate fix. Even if it's not in a noscript element it just makes sense to check if the element exists before trying to run things off it.

catch’s picture

Status: Reviewed & tested by the community » Fixed

#12 makes sense and explains some of my confusion.

Committed/pushed to 11.x, thanks!

Now that this issue is closed, please review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, please credit people who helped resolve this issue.

  • catch committed d9d467bc on 11.x
    Issue #3550388 by mfb, catch, nod_: 11.3 regression: Uncaught (in...

Status: Fixed » Closed (fixed)

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