Is there any possibly way to get Disqus to be lazy loaded in Drupal? Similar to this: http://www.myatus.com/2011/03/20/lazy-loading-disqus-in-wordpress/

I noticed that sites such as engadget are now lazyloading Disqus. Would be a great feature to have.

Proposed solution

* Allow admin to choose if Disqus should be lazy-loaded
* There can be 2 types of lazy-loading: on scroll and on click
* Lazy loading on scroll implies that Disqus is loaded when the user scrolls the disqus thread into view
** Preferably use IntersectionObserver API for better performance
** All JS from Disqus is not very performance-optimized, so at least we do our part
* Lazy loading on click implies that there will be a button showing the number of comments available – when clicked, the Disqus widget will be displayed

CommentFileSizeAuthor
#47 disqus-1508786-lazyload-intersectionobserver-47-1.x.patch10.81 KBckng
#46 disqus-1508786-lazyload-intersectionobserver-46-2.0.x.patch9.14 KBckng
#42 disqus-lazy-loading-1508786-42.patch11.46 KBasrob
#38 disqus-lazy-loading-1508786-38.patch11.84 KBasrob
#37 disqus-lazy-loading-1508786-37.patch13.62 KBasrob
#33 disqus-lazy-loading-1508786-33.patch9.26 KBasrob
#22 async_or_lazy_load_comment_count-13063683.patch12.55 KBspfaffly
#21 async_or_lazy_load_comment_count-13063679.patch12.52 KBspfaffly
#19 async_or_lazy_load_comment_count-13063637.patch11.9 KBspfaffly
#17 async_or_lazy_load-1508786-16.patch9.56 KBChris Matthews
#15 1508786_D8_lazy_load.patch9.59 KBunfrgivn
#9 interdiff.txt1.13 KBslashrsm
#9 1508786_9.patch11.38 KBslashrsm
#6 1508786_D8.patch11.38 KBslashrsm
#5 disqus-lazy-loading-1508786-5.patch8.92 KBgregnostic
#4 disqus-lazy-loading-1508786-4.patch9.44 KBgregnostic
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

RobLoach’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev

Would definitely speed up script performance to have it load asynchronously. I believe 7.x does some stuff to speed it up, but would be good to make sure it's in both 6 and 7.

SocialNicheGuru’s picture

I just ran into this. It is a necessary feature in my opinion.

joecanti’s picture

This would be great - its quite a large script.

But maybe it would be better aimed at a higher level - like lazyload blocks, or lazyload panel panes? That way a generic solution could be used for other stuff??

Thanks, Joe

gregnostic’s picture

Issue summary: View changes
Status: Active » Needs review
FileSize
9.44 KB

Attached is a patch to enable lazy loading of the Disqus comments script. I've added configuration options to enable/disable lazy loading, choose whether you want to lazy load the script based on when the comments scroll into view or whether the user clicks on an HTML element, and the class for elements to attach the click handler to.

We've had an internal review of this code, but another pair of eyes looking over this would be appreciated!

gregnostic’s picture

Re-rolled the patch with changes based on internal feedback.

slashrsm’s picture

Version: 7.x-1.x-dev » 8.x-1.x-dev
FileSize
11.38 KB

Thanks! Looks OK but needs to go into D8 branch first. Here is quick port. Tested it really briefly and it seems to work. Some more testing would be more than welcome.

JayeshSolanki’s picture

Tested the patch for both the branches; lazy loading works great!
but I see that the disqus comment count did not load. Please check if this bug could be reproduced.

just some minor nitpicks

+++ b/disqus.js
@@ -14,12 +14,32 @@ var disqus_def_email = '';
 var disqus_config;
 
 (function ($) {
+Drupal.disqus = {
+  loadCommentScript: function (shortname) {
+    // Make the AJAX call to get the Disqus comments.
+    this.loadScript(shortname, 'embed.js')
+  },

missing semicolon

@@ -166,4 +177,25 @@ class DisqusCommentManager implements DisqusCommentManagerInterface {
     return $data;
   }
 
+  /**
+   * Assembles data about lazy loading.
+   *
+   * @return array
+   */
+  function lazy_load_settings() {
+    $data = array();
+
+    switch (\Drupal::config('disqus.settings')->get('advanced.lazy_loading.method')) {
+      case DisqusCommentManager::DISQUS_LAZY_LOAD_ON_SCROLL:
+       $data['lazyLoadMethod'] = 'scroll';
+        break;

needs an extra space after $data['lazyLoadMethod'] = 'scroll'; (in d8 patch)

JayeshSolanki’s picture

Status: Needs review » Needs work
slashrsm’s picture

Status: Needs work » Needs review
FileSize
11.38 KB
1.13 KB

Fixed nitpiks.

Count bug is unrelated to this patch. It doesn't work even in HEAD. I suspect this problem is related to the way D8 loads links (via AJAX request). Currently we load count only once. We probably need to load it after AJAX request.

slashrsm’s picture

vincer’s picture

It seems that this is, in part, for disqus-7.x-1.x-dev. Is there an order in which these patches should be applied? I'm just not clear on how to apply these files.

dawehner’s picture

  1. diff --git a/config/install/disqus.settings.yml b/config/install/disqus.settings.yml
    index 25563e1..e5a465a 100644
    
    index 25563e1..e5a465a 100644
    --- a/config/install/disqus.settings.yml
    
    --- a/config/install/disqus.settings.yml
    +++ b/config/install/disqus.settings.yml
    
    +++ b/config/install/disqus.settings.yml
    @@ -14,3 +14,7 @@ advanced:
    
    @@ -14,3 +14,7 @@ advanced:
         disqus_sso: false
         disqus_use_site_logo: false
         disqus_logo: ''
    +  lazy_loading:
    +    status: 0
    +    method: 'scroll'
    

    Needs config schema

  2. +++ b/disqus.js
    @@ -18,6 +18,28 @@ var disqus_config;
    +  },
    +  loadScript: function (shortname, scriptName) {
    +    $.ajax({
    

    I'm wondering whether we should validate shortname to ensure that we don't request an arbitrary external script?

  3. +++ b/disqus.js
    @@ -18,6 +18,28 @@ var disqus_config;
    +      cache: false
    

    Is there a reason for that?

  4. +++ b/disqus.module
    @@ -226,11 +226,17 @@ function disqus_theme() {
    +    'disqus_lazy_load' => array(
    +      'variables' => array('children' => NULL),
    +    ),
    
    @@ -240,6 +246,24 @@ function theme_disqus_noscript() {
    +function theme_disqus_lazy_load($variables) {
    +  if (\Drupal::config('disqus.settings')->get('advanced.lazy_loading.status') && \Drupal::config('disqus.settings')->get('advanced.lazy_loading.method') == 'click') {
    +    return '<p class="disqus-lazy-load">' . t('View the discussion thread.') . '</p>' . $variables['children'];
    +  }
    +  else {
    +    return $variables['children'];
    +  }
    +}
    +
    

    This would use a template now by default, so I guess we should convert that.

pribeh’s picture

I've tested the patch from #5 on the latest 7.12 and it works great.

pribeh’s picture

@gregnostic Count no longer works after applying the patch in #5 for 7.x for me.

unfrgivn’s picture

Thank you so much slashrsm for your initial work on this. I have updated your patch to work for Drupal 8.2.x

I didn't test this throughly but it applies successfully via composer now and it works on the front-end via button click. I had to replace the lazy load theme method with a twig template in the templates dir. You would need to modify or override this template in order to change the button look/text.

My apologies if this was not done "properly", I usually work on proprietary modules and so I haven't contributed a ton to Drupal.org

Chris Matthews’s picture

Here is a new D8 patch that simply fixes the whitespace errors in the #15 patch

1508786_D8_lazy_load.patch:149: trailing whitespace.
  
1508786_D8_lazy_load.patch:189: trailing whitespace.
    
1508786_D8_lazy_load.patch:220: trailing whitespace.
    
1508786_D8_lazy_load.patch:227: trailing whitespace.
    
1508786_D8_lazy_load.patch:243: trailing whitespace.
Chris Matthews’s picture

spfaffly’s picture

Thanks @slashrsm and @chris-matthews

I piggy-backed off your patch to add Comment Count functionality to the "Show Comments" button.

Patch below.

spfaffly’s picture

spfaffly’s picture

Forgot to add untracked template file. Rerolled patch. Also fixed issue with undefined variable.

spfaffly’s picture

Patch added.

spfaffly’s picture

dawehner’s picture

Can someone document what this patch is solving in the issue summary? Why we are loading the comment count when we just want to lazy load JS files? Maybe I'm missing something though.

spfaffly’s picture

@dawehner

My apologies - my work is built on top of the lazy load JS file functionality and wanted to provide the code here just in case.

If needed once the lazy load JS file functionality is merged I can reroll the files into a separate patch/issue.

Thanks!

jigarius’s picture

Thumbs up for this issue. Enabling the Disqus comments pulls down my site's page speed score from 90s all the way down to 50s.

jigarius’s picture

I see that there's a patch for this problem, but that it doesn't use an IntersectionObserver. Most modern browsers support it and it will be worth it to take a look. I'll try the patch soon.

Here's how I'm solving the issue for my site:

1. Create a checkbox in Disqus settings saying whether to lazy load the Disqus thread
2. If lazy loading is enabled and if the browser does not support IntersectionObserver, there will be no lazy loading. It might be tempting to create our own intersection observer, but all modern browsers already support them or will eventually support them. So, it is better not to write additional code which will be deprecated soon.
3. If lazy loading is enabled and the browser supports IntersectionObserver, then attach an intersection observer which will load the Disqus thread when the user scrolls down to the comments area.

While we're working on the disqus.js file building this feature, we can also do some cleanup (optional). Like using $ sign instead of jQuery and breaking things into 2 behaviors, one for comment counts and one for the thread.

jigarius’s picture

Just tested the patch in #22 and it works very well. Thanks! It would've been better to use an Intersection observer rather than a scroll observer. Also, there are many disqus_* variables in the global namespace (not created by the patch), it will be better to put them inside the Drupal.disqus namespace to keep the global namespace cleaner. This can be done as a separate task though.

The new lazyloading settings are not present in the config schema.

As for the comment counts, can we not simply detect if there is a comment-count related HTML element on the page? If some element needs a comment count, we load them, otherwise, we don't – one less setting to manage. For example, the thread is only required when the page contains a div#disqus_thread element. In the same way, the comment count should only be loaded when there are relevant elements present on the page.

spfaffly’s picture

jigarius’s picture

Title: async or lazy load » Lazy load / async load Disqus libraries for better performance
jigarius’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

The patch in comment #22 has worked for me and it's deployed to my prod site. I'll let the maintainers take it from here. If you're a maintainer please see my previous comment number 27. At least the config schema needs to be updated – the rest is optional I guess. Kindly make sure you credit the right people.

renguer0’s picture

I installed the patch #22. The configuration page, button and comment counts works (plus twig template) but when I click in "Show comments" button, nothing happens. In configuration page, I setted up the default class on button that I saw in twig template.

Console of Chrome debug don't show any errors at all. What can I do?

EDIT: Enabling comments when scroll down works. Thanks for that!!

renguer0’s picture

Status: Reviewed & tested by the community » Needs review
asrob’s picture

Updated patch for version 7.x.

dzepol’s picture

I tried to apply the patch from #33 but it says this hunk is rejected. The rejections occur whether or not I apply against the dev or the lastest version of 7.

diff a/disqus.module b/disqus.module    (rejected hunks)
@@ -149,6 +159,10 @@ function disqus_element_post_render($children, &$element) {
     $element['#attached']['js'][] = drupal_get_path('module', 'disqus') . '/js/disqus_ga.js';
   }
 
+  if (variable_get('disqus_lazy_load', FALSE)) {
+    $disqus += disqus_lazy_load_settings();
+  }
+
   /**
    * Pass callbacks on if needed. Callbacks array is two dimensional array
    * with callback type as key on first level and array of JS callbacks on the
jigarius’s picture

Since Drupal Core has started an initiative to remove jQuery usage, I have started the initiative of removing jQuery dependency from visitor-facing scripts of the Disqus module.

I'd request you to help test those changes because after they're merged, I will help fix this issue without jQuery asap so that your pages load faster without jQuery and lazy-loaded Disqus comments :D

DamienMcKenna’s picture

asrob’s picture

I've updated a patch to work with version 2.0.1-alpha1 because I've to use it with Drupal 9.

asrob’s picture

I've updated a patch to work with version 2.0.1-alpha4.

gaurav.kapoor’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
DamienMcKenna’s picture

Status: Needs review » Needs work

The patch doesn't apply against the 2.0.x branch.

chike’s picture

Patch #38 broke the module on 2.0.1-alpha5. The comments stopped loading.

asrob’s picture

Updated patch to work with 2.0.1-alpha5.

gaurav.kapoor’s picture

Status: Needs work » Needs review
chike’s picture

After applying patch #42, visiting configuration page throws a white screen with this error:

Class 'Drupal\disqus\Form\DisqusCommentManager' not found in Drupal\disqus\Form\DisqusSettings Form->buildForm() (line 293 of C:\wamp64\www\site\modules\contrib\disqus\src\Form\DisqusSettingsForm.php)

gaurav.kapoor’s picture

Status: Needs review » Needs work
ckng’s picture

Lazy load via IntersectionObserver version. Changes and improvements

  • Simplified options and placed under Behavior.
  • Since we're lazy loading, using `defer` instead of `async` for all scripts.
  • Removed click and scroll, replaced with IntersectionObserver.
  • On browser without IntersectionObserver, it will load directly.
ckng’s picture

Version: 2.0.x-dev » 8.x-1.x-dev
FileSize
10.81 KB

Backported IntersectionObserver version to 1.x. No tests, since there is none setup for 1.x.

ckng’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
dpagini’s picture

This is marked as for the 2.x branch, but there is no patch for that branch right now... should this go back to "needs work" then? I'm happy to test out a patch for 2.x, but I'm a little lost on what the patch is doing exactly.

dpagini’s picture

Status: Needs review » Reviewed & tested by the community

Oh this is my bad. I did not read close enough that #47 was a backport for 1.x, but #46 already existed for 2.x. Once I took some time and read slowly, I pulled in that patch on my site, and tested it out, and my PageSpeed scores were significantly improved. Marking as RTBC.

IT-Cru’s picture

Patch #46 worked so far for me, but I see some possible improvements we could maybe also integrate.

  • Split disqus.js and disqus.settings.js in two different libraries definitions, because disqus.settings.js seems to be only required for Drupal's Disqus settings form.
  • Switch from var to let/const syntax in all JS files.
  • Try to remove jQuery once and if possible also jQuery dependency from disqus.js to avoid extra loading of jQuery.
  • Simplify all if (settings.disqus.language || false) { to if (settings.disqus.language) {.
  • For better readability add extra lines between each libraries definition in disqus.libraries.yml file.
  • It seems var disqus_lazy_load = 0; is never used.

@ckng: what do you think about possible improvements? Should we maybe set this issue back to needs work?

I've also linked related issue where already in the past some work was done to remove jQuery from disqus.js.

jigarius’s picture

@ IT-Cru IMHO if we have some improvement which is ready to be merged, we should include that as it is for now. I say so because this issue has been open for a long time now. Every time there is a working patch, some other thing changes in the module which makes the patch become stale. So, if we have it working this time, we should merge what we have so that we at least remove of the jQuery dependency. Later, we can create another PR to separate the admin JS from the user-facing JS.

What do you think?

IT-Cru’s picture

@jigarius: Complete fine for me. This is why I'm not switched it back to needs work and only mentioned possible additional improvements I see for near future fixing issues. It also make it easier when it is merged and rebase existing MRs like added linked issue which already remove usage of jQuery.

Better to split other improvements into small tasks which could be easier tested :)