-
Notifications
You must be signed in to change notification settings - Fork 815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infinite scroll: rewrite from jQuery to vanilla JS #15017
Conversation
This is an automated check which relies on |
@@ -215,23 +215,6 @@ public function action_wp_enqueue_scripts() { | |||
if ( Jetpack::is_module_active( 'tiled-gallery' ) ) { | |||
Jetpack_Tiled_Gallery::default_scripts_and_styles(); | |||
} | |||
|
|||
// Core's Audio and Video Shortcodes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, IS loads wp-mediaelement
eagerly on all pages, which is inefficient. Also, the wp-mediaelement
script depends on jquery
, which makes matters even worse.
WordPress will enqueue wp-mediaelement
when a media element that requires it (e.g. [audio]
) appears on any particular page. Infinite scroll is responsible for loading these assets only when it injects any media elements on subsequent pages. This and the related fixes (1, 2) accomplish just that.
@@ -0,0 +1,54 @@ | |||
/* globals wp */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved all purely Customizer logic into its own file and retained its coupling to jQuery
, because the aim of this PR is to rewrite front-end code to vanilla JS.
this.click_handle = settings.click_handle; | ||
this.google_analytics = settings.google_analytics; | ||
this.history = settings.history; | ||
this.origURL = window.location.href; | ||
this.pageCache = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocker: Removing page caching is a major change, which needs to be further analyzed and discussed.
I've consolidated all changes to pageCache
to a single commit to make is simple for us to revert them if necessary. Please read the commit message, it contains more details about why this change is being made.
While I understand the reason for implementing the cache the way it's implemented right now, I wasn't able to verify it's actually efficient. Removed nodes from the invisible "pages" from DOM currently don't seem to be garbage collected. I've profiled the memory using Chrome Dev tools and the number of Nodes in memory stayed constant even as they were removed from DOM. I'm not sure why that is, these are my two theories:
- My machine has enough memory and doesn't need to GC aggressively.
- The Nodes remain to be referenced somewhere even after they are removed (likely in jQuery internally).
I'll try to construct a more representative test page with a lot of dynamically loaded content and try to verify whether memory can actually be freed by dynamically removing Nodes like this.
/** | ||
* Recursively convert a JS object into URL encoded data. | ||
*/ | ||
Scroller.prototype.urlEncodeJSON = function( obj, prefix ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Usually we could just POST
with Content-Type: application/json
, but that would send the JSON string in the body of the request and we would need to rewrite much of infinity.php
to adapt to that.
Instead we URI encode the data object, so that we can send the parameters as application/x-www-form-urlencoded
, which is correctly and automatically decoded by PHP and the $_POST
($_REQUEST
) superglobals are correctly populated.
jqxhr.done( function( response ) { | ||
xhr.onload = function() { | ||
var response = JSON.parse( xhr.responseText ), | ||
httpCheck = xhr.status >= 200 && xhr.status < 300, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: It's fine to check for 2xx
response codes only. All redirects are followed by xhr
and should never be exposed to us.
0% { opacity: 1 } | ||
100% { opacity: 0 } | ||
} | ||
.infinite-loader .spinner-inner div { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you switch to tabs instead of spaces in this file? This way this will ensure that the next person making a change in that file does not inadvertently make changes on all lines on save.
modules/infinite-scroll/infinity.php
Outdated
array( 'jquery' ), | ||
'4.0.0', | ||
array(), | ||
'8.4.0', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can switch to using JETPACK__VERSION
here and below maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is amazing, thank you! I have tested the code, it seems to be working fine with both button and scroll triggering. I have made two comments in the code, but there's nothing major.
modules/infinite-scroll/infinity.js
Outdated
@@ -517,16 +663,16 @@ | |||
self.ready = true; | |||
self.refresh(); | |||
} else { | |||
self.body.unbind( 'post-load', self.checkViewportOnLoad ); | |||
self.body.addEventListener( 'post-load', self.checkViewportOnLoadBound ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure of the logic here, but should this be removeEventListener
instead?
modules/infinite-scroll/infinity.js
Outdated
@@ -596,33 +746,7 @@ | |||
} else { | |||
setsHidden.push( { id: id, top: setTop, bottom: setBottom, pageNum: setPageNum } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing setsHidden
being used anywhere in this method's scope after the array is populated, aside from the removed block where it was stored in the page cache. Maybe we can remove the array population as well?
modules/infinite-scroll/infinity.js
Outdated
this.body.addEventListener( 'post-load', self.initializeMejs ); | ||
}; | ||
|
||
Scroller.prototype.triggerEvent = function( eventName, el, data ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocker: Events need to be triggered in a backwards-compatible fashion. See this commit for sample implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in fda8991.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the fixes, looks good to me now!
@jeherve Assigning to you to re-review, please. Also, question: who is usually the assignee of a PR on the Jetpack project? Is it the person responsible for the "next step" or is always the PR author? I would like to be respectful of the process here, but I'm not sure what it is. |
r204969-wpcom |
@dero Found an interesting situation. @sergeymitr spotted that if you scroll down using the keyboard (down button), new posts are inserted pretty quickly to the point of loading ~10 pages worth of posts before scrolling through the initial page load. See https://cloudup.com/c9xX-6_P3dt I'm okay merging this PR if you're able to debug that in a follow-up PR in the next couple of days. |
@kraftbj Sure thing, I can debug this tomorrow and (if needed) on Monday. Do you know if this happens in all browsers? I wasn't able to verify the issue in Chrome, but the posts on my test site are displayed with full content, which is different from your test. I can spend more time on the issue tomorrow. |
Sergey kept digging: So here's the summary: |
@kraftbj Thank you for this additional detail. I have a Windows machine and can test it out - but not before tomorrow. If you have more detail before then, I'd be happy if you could post it. |
@kraftbj Update: I can reproduce in Chrome on Ubuntu, but only on |
@kraftbj Last update tonight: I'm seeing the same issue on the existing It seems that the container element in I'm going to return to this ticket tomorrow. |
@dero Nice find. I'm going to go ahead and merge this (since you're right, this is happening on master too; I didn't catch that). A quick PR tomorrow/Monday for that will be easy to get in before the EOD Monday code freeze for 8.4. I don't want to hold this up from landing in 8.4 if something happens and we can't address twentyseventeen in time for freeze. |
Opened #15155 for tracking. |
* Initial changelog entry * Changelog: add #14904 * Changelog: add #14910 * Changelog: add #14913 * Changelog: add #14916 * Changelog: add #14922 * Changelog: add #14924 * Changelog: add #14925 * Changelog: add #14928 * Changelog: add #14840 * Changelog: add #14841 * Changelog: add #14842 * Changelog: add #14826 * Changelog: add #14835 * Changelog: add #14859 * Changelog: add #14884 * Changelog: add #14888 * Changelog: add #14817 * Changelog: add #14814 * Changelog: add #14819 * Changelog;: add #14797 * Changelog: add #14798 * Changelog: add #14802 * Changelog: add #13676 * Changelog: add #13744 * Changelog: add #13777 * Changelog: add #14446 * Changelog: add #14739 * Changelog: add #14770 * Changelog: add #14784 * Changelog: add #14897 * Changelog: add #14898 * Changelog: add #14968 * Changelog: add #14985 * Changelog: add #15044 * Changelog: add #15052 * Update to remove Podcast since it remains in Beta * Changelog: add #14803 * Changelog: add #15028 * Changelog: add #15065 * Changelog:add #14886 * Changelog: add #15118 * Changelog: add #14990 * Changelog: add #14528 * Changelog: add #15120 * Changelog: add #15126 * Changelog: add #15049 * Chanegelog: add #14852 * Changelog: add #15090 * Changelog: add #15138 * Changelog: add #15124 * Changelog:add #15055 * Changelog: add #15017 * Changelog: add #15109 * Changelog: add #15145 * Changelog:add #15096 * Changelog:add #15153 * Changelog: add #15133 * Changelog: add #14960 * Changelog: add #15127 * Changelog: add #15056 * Copy current changelog to changelog archive. * Clarify changelog description
Fixes #14862
Changes proposed in this Pull Request:
infinite-scroll.js
.This is a large change, please see comments inline of this PR for additional detail on how certain features continue to be supported in vanilla JS.
Is this a new feature or does it add/remove features to an existing part of Jetpack?
infinite-scroll
module.Testing instructions:
Simple IS (button trigger):
Older Posts
button is rendered.Older Posts
button not being rendered.Simple IS (automatic trigger):
IS with audio / video shortcodes:
There is a good deal of code dedicated to making sure the
[audio]
and[video]
shortcodes still work when infinite scroll is enabled. These shortcodes use theMediaElementJS
from WP core to normalize media playback experience and that library is finicky and requires a lot of special treatment. TheMediaElement
library depends on jQuery and IS needs to be able to dynamically injectMediaElement
andjQuery
scripts lazily only when required.[audio]
and / or[video]
shortcodes to a post that will appear on a second page of the homepage, i.e. that post should be loaded by IS.jQuery
andwp-mediaelement
scripts are not loaded on the initial page load.jQuery
andwp-mediaelement
scripts are now loaded and executed dynamically.mejs-container
classes).IS (customizer):
Tested in:
Proposed changelog entry for your changes: