Skip to content
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

Delay block hydration to allow interactive block stores to initialize #66772

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

westonruter
Copy link
Member

Fixes #66691.

When scheduler.yield() is available, the splitTask() function is implemented to use it. When a task is split with scheduler.yield() it results in the tail being added to the front of the task queue. In contrast, when splitTask() is implemented with setTimeout() (when scheduler.yield() is not available), then the tail of the split task is added to the end of the task queue. It appears there is a race condition between the call to init.

In particular, given this init function:

// Initialize the router with the initial DOM.
export const init = async () => {
const nodes = document.querySelectorAll(
`[data-${ directivePrefix }-interactive]`
);
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 );
}
}
};

It is getting invoked before the code in a block's view.js is invoked, for example:

const { state, actions, callbacks } = store(

When splitTask() is was using setTimeout() then the calls to await splitTask() had the effect of delaying the hydration until after the blocks' view modules execute. But when splitTask() is implemented with scheduler.yield() the hydration logic is executing before the interactive blocks' view module (i.e. the store initialization) executes.

Of note, the error also occurs if await splitTask() is eliminated from init function as well, indicating that it was not correctly accounting for delaying the Interactivity API's init until after the interactive blocks have all initialized. There seems to be a dependency problem here, where hydration of an interactive block should be blocked until its corresponding view script module has loaded. This seems to be related to:

In the mean time, adding a setTimeout() to handle the delay seems to do the trick.

Code execution with splitTask implemented with setTimeout

export const init = async () => {
const nodes = document.querySelectorAll(
`[data-${ directivePrefix }-interactive]`
);
for ( const node of nodes ) {
if ( ! hydratedIslands.has( node ) ) {
await splitTask();

const { state, actions, callbacks } = store(

const fragment = getRegionRootFragment( node );
const vdom = toVdom( node );
initialVdom.set( node, vdom );
await splitTask();
hydrate( vdom, fragment );
}
}
};

Code execution with splitTask implemented with scheduler.yield

// Initialize the router with the initial DOM.
export const init = async () => {
const nodes = document.querySelectorAll(
`[data-${ directivePrefix }-interactive]`
);
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 );
}
}
};

const { state, actions, callbacks } = store(

@westonruter westonruter added [Type] Bug An existing feature does not function as intended [Packages] Interactivity /packages/interactivity labels Nov 5, 2024
Copy link

github-actions bot commented Nov 5, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: westonruter <[email protected]>
Co-authored-by: annezazu <[email protected]>
Co-authored-by: artemiomorales <[email protected]>
Co-authored-by: cbravobernal <[email protected]>
Co-authored-by: t-hamano <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Packages] Interactivity /packages/interactivity [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image Block: Lightbox does not work
1 participant