Problem

When BigPipe (8.1.x rc1) is enabled, and the user is logged in. Disqus comments will not load.

However even when Disqus does not load, the following HTML exists.

<div data-quickedit-field-id="node/24/field_disqus/und/full">
<div id="disqus_thread">
<noscript>
  <p>
    <a href="http://localhost:8080/node/24">View the discussion thread.</a>
  </p>
</noscript>
</div>
</div>

Note that the Disqus field is not delivered using the BigPipe mechanism even if BigPipe is active.

Now when BigPipe is enabled, the ajax call in disqus.js that loads embed.js from disqus.com is not executed. (Line 69 in disqus.js)

        // Make the AJAX call to get the Disqus comments.
        jQuery.ajax({
          type: 'GET',
          url: '//' + disqus_shortname + '.disqus.com/embed.js',
          dataType: 'script',
          cache: false
        });

If I manually run this code in the console after the page is loaded, it will then load embed.js from disqus.com and the comment will load normally.

CommentFileSizeAuthor
#23 interdiff-14-23.txt496 bytesAnonymous (not verified)
#23 disqus-2691401-23.patch1.87 KBAnonymous (not verified)
#14 disqus-2691401-1.patch1.96 KBAnonymous (not verified)

Comments

Anonymous’s picture

ztl8702 created an issue. See original summary.

wim leers’s picture

Cross-posting from #2690589-9: Disqus comments not loading when BigPipe is installed:

The Disqus module is poorly written. It does this:

$('body').once('disqus').each(function() {
  if (settings.disqus || false) {

… but when BigPipe is enabled, drupalSettings.disqus is only set later. This would also be the case if the part of the page containing Disqus comments is loaded via AJAX — this is not a BigPipe-specific problem.

So, the conclusion is simple: the Disqus module's JS needs to be fixed.

Anonymous’s picture

Yes, it looks like we should re-run the checking after each AJAX call. I am working on a patch now. I am not sure whether simply removing .once() will work. Probably needs more work.

Anonymous’s picture

I put the following debug code inside the disqus behavior, outside .once():

console.log("Disqus behavior called: ");
console.log(settings.disqus);

But when I load the page I got the following logs:

Disqus behavior called: 
undefined 
Disqus behavior called:  
undefined 

...

Disqus behavior called: 
undefined

It turns out the behavior is indeed called after each AJAX call, however even in the last call (when BigPipe should have already done loading), the disqus setting is still undefined.

This is strange.

Anonymous’s picture

Wim Leers, it turns out that drupalSettings.disqus is never set when BigPipe is enabled.

When BigPipe is enabled (logged in), console.log(drupalSettings) returns:

Object { path: Object, pluralDelimiter: "", ajaxPageState: Object, ajaxTrustedUrl: Array[0], bigPipePlaceholderIds: Object, disqusComments: "someid", toolbar: Object, user: Object, dialog: Object, editor: Object }

When BigPipe is NOT enabled, console.log(drupalSettings) returns:

Object { path: Object, pluralDelimiter: "", disqusComments: "someid", disqus: Object, user: Object }

If we look at the response, disqus settings are not included in both the initial drupalSettings object nor in the second flush by BigPipe.

The disqusComments object, however, does load no matter BigPipe is enabled or not.

wim leers’s picture

Assigned: Unassigned » wim leers

I'll take a quick look.

nod_’s picture

My guess is missing dependency on core/drupalSettings.

wim leers’s picture

Assigned: wim leers » Unassigned

That'd be a great guess indeed.

Unassigning, clearly I got sidetracked.

Anonymous’s picture

Assigned: Unassigned »
Anonymous’s picture

@nod_ Adding core/drupalSettings to disqus.libraries.yml does not help, as far as I have tested.
What I find strange is that the disqusComments property is always set in drupalSettings, regardless of whether BigPipe is enabled or not.

Anonymous’s picture

Umm... Looks like the callback function for the placeholder of Disqus Element is not called, which is where the disqus settings are attached to drupalSettings.

Let me see why that happened.

Anonymous’s picture

Interestingly, the placeholder generated by Disqus module has been overridden by BigPipe, but somehow this placeholder does not appears in the final HTML. The Disqus Element is rendered as if it is not served via BigPipe, however its callback function is never called.

In my case, BigPipe replaced two HTML placeholders, StatusMessages, and DisqusComments; however, only StatusMessages one appears in the preBody.

Anonymous’s picture

OK. I think I have located where the error is.

In Disqus.php, it does this:

public function getInfo() {
    return array(
        
      '#title' => '',
      '#url' => '',
      '#identifier' => '',
      '#callbacks' => '',
      '#theme_wrappers' => ['disqus_noscript', 'container'],
      '#attributes' => ['id' => 'disqus_thread'],
      '#pre_render' => [
        get_class() . '::generatePlaceholder',
      ],
    );
  }

I think this causes the Disqus placeholder to be rendered instead of the BigPipe placeholder.

After changing this function to:

public function getInfo() {
    return array(
      '#pre_render' => [
        get_class() . '::generatePlaceholder',
      ],
    );
  }

The disqus object will appear in drupalSettings. Now we just need to fix the javascript.

Anonymous’s picture

StatusFileSize
new1.96 KB

So here is the patch.

What I did:

  • Removed several properties from the array in getInfo(), as stated above;
  • Fixed disqus.js so that it will check if Disqus should be loaded after every AJAX call. (while still ensuring that Disqus will only be loaded once)

The patch works for me. Please help with testing. Thanks.

skyredwang’s picture

Status: Active » Needs review
fabianx’s picture

Status: Needs review » Needs work

I think the JS fix is fine, but to remove the properties feels a little wrong.

I think if possible this should use a #builder instead of #pre_render as it clearly can be rendered independently and then the render array inside the builder should have the other properties.

Anonymous’s picture

Status: Needs work » Needs review

@Fabianx
in src/Element/Disqus.php
function generatePlaceholder looks like this:


  public static function generatePlaceholder(array $element) {
    if (\Drupal::currentUser()->hasPermission('view disqus comments')) {
      $element[] = [
        '#lazy_builder' => [
          get_class() . '::displayDisqusComments',
          [
            $element['#title'],
            $element['#url'],
            $element['#identifier'],
          ]
        ],
        '#create_placeholder' => TRUE,
      ];
    }

    return $element;
  }

And function displayDisqusComments adds #theme_wrappers and #attributes.

  public static function displayDisqusComments($title, $url, $identifier) {
    $disqus_settings = \Drupal::config('disqus.settings');
    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');
    $element = [
      '#theme_wrappers' => ['disqus_noscript', 'container'],
      '#attributes' => ['id' => 'disqus_thread'],
    ];

and 'title', 'url', 'identifier' finally gets set in the callback function.

    $disqus = [
      'domain' => $disqus_settings->get('disqus_domain'),
      'url' => $url,
      'title' => $title,
      'identifier' => $identifier,
      'disable_mobile' => $disqus_settings->get('behavior.disqus_disable_mobile'),
    ];

That's why I don't think they need to be set in the first function. Tell me if I am wrong.

slashrsm’s picture

+++ b/src/Element/Disqus.php
@@ -21,12 +21,6 @@ class Disqus extends RenderElement {
-      '#title' => '',
-      '#url' => '',
-      '#identifier' => '',

Should we make sure those are not empty to prevent notices?

At least identifier is actually required. Should we throw an exception if it is not set?

Anonymous’s picture

@slashrsm

I think you are right. What really matters is only '#theme_wrappers'.

slashrsm’s picture

Identifier seems to be important to, right? And if user doesn't supply title, url or identifier we will get notices in generatePlaceholder().

Anonymous’s picture

@slashrsm,
Yes. So we only remove '#theme_wrappers'.
I will test it shortly.

omlx’s picture

any update ?

Anonymous’s picture

StatusFileSize
new1.87 KB
new496 bytes

@omlx
Sorry I forgot.
A simple fix. Could you try it out?

omlx’s picture

@ztl8702 Thanks, It works for me.

  • slashrsm committed 1128fef on 8.x-1.x authored by ztl8702
    Issue #2691401 by ztl8702, Wim Leers, slashrsm, omlx, Fabianx: Ensure...
slashrsm’s picture

Status: Needs review » Fixed

Committed.

Status: Fixed » Closed (fixed)

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