-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Interactivity API: Defer hydration until node is scrolled near the viewport #58284
base: trunk
Are you sure you want to change the base?
Changes from 17 commits
645c945
6ac9d62
cffdb4d
4cc10a7
3770575
1f845c9
d0587db
cfe2b04
d580cce
fb15565
3ec8de5
6b95333
5532ee4
08720c4
d27985e
88d679c
abd3747
387ab6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -29,6 +29,38 @@ export const initialVdom = new WeakMap< Element, ComponentChild[] >(); | |||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Initialize the router with the initial DOM. | ||||||||||||||||||||||||||
export const init = async () => { | ||||||||||||||||||||||||||
let observedNodeCount = 0; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const intersectionObserver = new window.IntersectionObserver( | ||||||||||||||||||||||||||
async ( entries ) => { | ||||||||||||||||||||||||||
for ( const entry of entries ) { | ||||||||||||||||||||||||||
if ( ! entry.isIntersecting ) { | ||||||||||||||||||||||||||
continue; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const node = entry.target; | ||||||||||||||||||||||||||
intersectionObserver.unobserve( node ); | ||||||||||||||||||||||||||
observedNodeCount--; | ||||||||||||||||||||||||||
if ( observedNodeCount === 0 ) { | ||||||||||||||||||||||||||
intersectionObserver.disconnect(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if ( ! hydratedIslands.has( node ) ) { | ||||||||||||||||||||||||||
const fragment = getRegionRootFragment( node ); | ||||||||||||||||||||||||||
const vdom = toVdom( node ); | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the old logic, this used to populate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems this is a merge conflict resolution on my part. This may be needed: --- a/packages/interactivity/src/init.ts
+++ b/packages/interactivity/src/init.ts
@@ -48,6 +48,7 @@ export const init = async () => {
if ( ! hydratedIslands.has( node ) ) {
const fragment = getRegionRootFragment( node );
const vdom = toVdom( node );
+ initialVdom.set( node, vdom );
await splitTask();
hydrate( vdom, fragment );
await splitTask(); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it is only being used here: gutenberg/packages/interactivity-router/src/index.ts Lines 189 to 200 in ef7afef
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Introduced in #58496 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restored I found that this code in @DAreRodz For this page cache, is it a problem that |
||||||||||||||||||||||||||
await splitTask(); | ||||||||||||||||||||||||||
hydrate( vdom, fragment ); | ||||||||||||||||||||||||||
await splitTask(); | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this yield at the end of the process? In the original code that happened before, right above the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I recall, I moved it here because given that this is now inside of an |
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||
root: null, // To watch for intersection relative to the device's viewport. | ||||||||||||||||||||||||||
rootMargin: '100% 0% 100% 0%', // Intersect when within 1 viewport approaching from top or bottom. | ||||||||||||||||||||||||||
threshold: 0.0, // As soon as even one pixel is visible. | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const nodes = document.querySelectorAll( | ||||||||||||||||||||||||||
`[data-${ directivePrefix }-interactive]` | ||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||
|
@@ -44,14 +76,8 @@ export const init = async () => { | |||||||||||||||||||||||||
setTimeout( resolve, 0 ); | ||||||||||||||||||||||||||
} ); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
observedNodeCount = nodes.length; | ||||||||||||||||||||||||||
for ( const node of nodes ) { | ||||||||||||||||||||||||||
if ( ! hydratedIslands.has( node ) ) { | ||||||||||||||||||||||||||
await splitTask(); | ||||||||||||||||||||||||||
const fragment = getRegionRootFragment( node ); | ||||||||||||||||||||||||||
const vdom = toVdom( node ); | ||||||||||||||||||||||||||
initialVdom.set( node, vdom ); | ||||||||||||||||||||||||||
await splitTask(); | ||||||||||||||||||||||||||
hydrate( vdom, fragment ); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
intersectionObserver.observe( node ); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}; |
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.
Something else to consider, perhaps for a future PR: What if new content is added to the page dynamically without using the Interactivity API? For example, what if there is a custom infinite scroll implementation that appends content to the page? In this case, the
disconnect()
here will mean that none of the new elements will get hydrated. This is no breakage compared with before, since any such nodes wouldn't get hydrated anyway since they aren't included in the initial list of nodes returned bydocument.querySelectorAll( '[data-wp-interactive]' )
. If we wanted to account for such nodes being added, then perhaps we should add aMutationObserver
which listens for new content being added to the page, and when it is added, look for any new nodes viaroot.querySelectorAll( '[data-wp-interactive]' )
whereroot
is the new element added.