summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/curly-bags-attack.md5
-rw-r--r--packages/astro/src/runtime/server/astro-island.ts31
-rw-r--r--packages/astro/src/runtime/server/render/component.ts2
3 files changed, 31 insertions, 7 deletions
diff --git a/.changeset/curly-bags-attack.md b/.changeset/curly-bags-attack.md
new file mode 100644
index 000000000..5148e0f46
--- /dev/null
+++ b/.changeset/curly-bags-attack.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fix hydration on slow connection
diff --git a/packages/astro/src/runtime/server/astro-island.ts b/packages/astro/src/runtime/server/astro-island.ts
index 710319aac..58eb7f2e0 100644
--- a/packages/astro/src/runtime/server/astro-island.ts
+++ b/packages/astro/src/runtime/server/astro-island.ts
@@ -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() {
diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts
index bfb82ceda..158a88a07 100644
--- a/packages/astro/src/runtime/server/render/component.ts
+++ b/packages/astro/src/runtime/server/render/component.ts
@@ -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 {