Fix hydration on slow connection (#8680)

This commit is contained in:
Bjorn Lu 2023-09-29 21:54:46 +08:00 committed by GitHub
parent c3572fd5e0
commit 31c59ad8b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix hydration on slow connection

View file

@ -56,17 +56,34 @@ declare const Astro: {
document.addEventListener('astro:after-swap', this.unmount, { once: true });
}
connectedCallback() {
if (!this.hasAttribute('await-children') || this.firstChild) {
if (
!this.hasAttribute('await-children') ||
document.readyState === 'interactive' ||
document.readyState === 'complete'
) {
this.childrenConnectedCallback();
} else {
// connectedCallback may run *before* children are rendered (ex. HTML streaming)
// If SSR children are expected, but not yet rendered,
// Wait with a mutation observer
new MutationObserver((_, mo) => {
// If SSR children are expected, but not yet rendered, wait with a mutation observer
// for a special marker inserted when rendering islands that signals the end of the island
const onConnected = () => {
document.removeEventListener('DOMContentLoaded', onConnected);
mo.disconnect();
// Wait until the next macrotask to ensure children are really rendered
setTimeout(() => this.childrenConnectedCallback(), 0);
}).observe(this, { childList: true });
this.childrenConnectedCallback();
};
const mo = new MutationObserver(() => {
if (
this.lastChild?.nodeType === Node.COMMENT_NODE &&
this.lastChild.nodeValue === 'astro:end'
) {
this.lastChild.remove();
onConnected();
}
});
mo.observe(this, { childList: true });
// in case the marker comment got stripped and the mutation observer waited indefinitely,
// also wait for DOMContentLoaded as a last resort
document.addEventListener('DOMContentLoaded', onConnected);
}
}
async childrenConnectedCallback() {

View file

@ -360,6 +360,8 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
if (island.children) {
island.props['await-children'] = '';
// Marker to signal that Astro island children is completed while streaming
island.children += `<!--astro:end-->`;
}
return {