From 1c77779dd66a6db77c81ed235da076a6118decde Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Fri, 26 May 2023 22:37:33 +0800 Subject: [PATCH] Fix `astro-static-slot` hydration mismatch error (#7196) --- .changeset/eleven-walls-explain.md | 7 +++++++ packages/astro/e2e/nested-in-react.test.js | 16 ++++++++++++++++ packages/astro/e2e/nested-in-vue.test.js | 16 ++++++++++++++++ packages/integrations/preact/src/static-html.ts | 4 ++-- packages/integrations/react/static-html.js | 2 +- packages/integrations/vue/static-html.js | 5 ++++- 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 .changeset/eleven-walls-explain.md diff --git a/.changeset/eleven-walls-explain.md b/.changeset/eleven-walls-explain.md new file mode 100644 index 000000000000..fd2772185718 --- /dev/null +++ b/.changeset/eleven-walls-explain.md @@ -0,0 +1,7 @@ +--- +'@astrojs/preact': patch +'@astrojs/react': patch +'@astrojs/vue': patch +--- + +Fix `astro-static-slot` hydration mismatch error diff --git a/packages/astro/e2e/nested-in-react.test.js b/packages/astro/e2e/nested-in-react.test.js index cd9bc2879de4..7fbe13c0be59 100644 --- a/packages/astro/e2e/nested-in-react.test.js +++ b/packages/astro/e2e/nested-in-react.test.js @@ -14,6 +14,22 @@ test.afterAll(async () => { }); test.describe('Nested Frameworks in React', () => { + test('No hydration mismatch', async ({ page, astro }) => { + // Get browser logs + const logs = []; + page.on('console', (msg) => logs.push(msg.text())); + + await page.goto(astro.resolveUrl('/')); + + // wait for root island to hydrate + const counter = page.locator('#react-counter'); + await waitForHydrate(page, counter); + + for (const log of logs) { + expect(log, 'React hydration mismatch').not.toMatch('An error occurred during hydration'); + } + }); + test('React counter', async ({ astro, page }) => { await page.goto(astro.resolveUrl('/')); diff --git a/packages/astro/e2e/nested-in-vue.test.js b/packages/astro/e2e/nested-in-vue.test.js index 6e7c6a5c2197..deed309c7fd9 100644 --- a/packages/astro/e2e/nested-in-vue.test.js +++ b/packages/astro/e2e/nested-in-vue.test.js @@ -14,6 +14,22 @@ test.afterAll(async () => { }); test.describe('Nested Frameworks in Vue', () => { + test('no hydration mismatch', async ({ page, astro }) => { + // Get browser logs + const logs = []; + page.on('console', (msg) => logs.push(msg.text())); + + await page.goto(astro.resolveUrl('/')); + + // wait for root island to hydrate + const counter = page.locator('#vue-counter'); + await waitForHydrate(page, counter); + + for (const log of logs) { + expect(log, 'Vue hydration mismatch').not.toMatch('Hydration node mismatch'); + } + }); + test('React counter', async ({ astro, page }) => { await page.goto(astro.resolveUrl('/')); diff --git a/packages/integrations/preact/src/static-html.ts b/packages/integrations/preact/src/static-html.ts index f0fbd885ca09..453e72b7f56c 100644 --- a/packages/integrations/preact/src/static-html.ts +++ b/packages/integrations/preact/src/static-html.ts @@ -13,9 +13,9 @@ type Props = { * As a bonus, we can signal to Preact that this subtree is * entirely static and will never change via `shouldComponentUpdate`. */ -const StaticHtml = ({ value, name, hydrate }: Props) => { +const StaticHtml = ({ value, name, hydrate = true }: Props) => { if (!value) return null; - const tagName = hydrate === false ? 'astro-static-slot' : 'astro-slot'; + const tagName = hydrate ? 'astro-slot' : 'astro-static-slot'; return h(tagName, { name, dangerouslySetInnerHTML: { __html: value } }); }; diff --git a/packages/integrations/react/static-html.js b/packages/integrations/react/static-html.js index 37fda1983ff0..e319a40c7b98 100644 --- a/packages/integrations/react/static-html.js +++ b/packages/integrations/react/static-html.js @@ -7,7 +7,7 @@ import { createElement as h } from 'react'; * As a bonus, we can signal to React that this subtree is * entirely static and will never change via `shouldComponentUpdate`. */ -const StaticHtml = ({ value, name, hydrate }) => { +const StaticHtml = ({ value, name, hydrate = true }) => { if (!value) return null; const tagName = hydrate ? 'astro-slot' : 'astro-static-slot'; return h(tagName, { diff --git a/packages/integrations/vue/static-html.js b/packages/integrations/vue/static-html.js index 34740f88ff06..885319026077 100644 --- a/packages/integrations/vue/static-html.js +++ b/packages/integrations/vue/static-html.js @@ -10,7 +10,10 @@ const StaticHtml = defineComponent({ props: { value: String, name: String, - hydrate: Boolean, + hydrate: { + type: Boolean, + default: true, + }, }, setup({ name, value, hydrate }) { if (!value) return () => null;