From afcb9d331179287629b5ffce4020931258bebefa Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 26 Feb 2024 03:38:11 -0500 Subject: [PATCH] Fix hydration scripts missing from dynamic slot usage (#10219) --- .changeset/dirty-boats-suffer.md | 5 +++ packages/astro/src/core/render/result.ts | 2 +- packages/astro/src/runtime/server/escape.ts | 2 ++ .../src/components/WithSlot.astro | 16 +++++++++ .../hydration-race/src/pages/slot.astro | 34 +++++++++++++++++++ packages/astro/test/hydration-race.test.js | 11 ++++++ 6 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 .changeset/dirty-boats-suffer.md create mode 100644 packages/astro/test/fixtures/hydration-race/src/components/WithSlot.astro create mode 100644 packages/astro/test/fixtures/hydration-race/src/pages/slot.astro diff --git a/.changeset/dirty-boats-suffer.md b/.changeset/dirty-boats-suffer.md new file mode 100644 index 000000000000..9ca1d994a60a --- /dev/null +++ b/.changeset/dirty-boats-suffer.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fix dynamic slots missing hydration scripts diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index cc7fa219e9c2..1e6f6f35a185 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -114,7 +114,7 @@ class Slots { const slot = async () => typeof expression === 'function' ? expression(...args) : expression; return await renderSlotToString(result, slot).then((res) => { - return res != null ? String(res) : res; + return res; }); } // JSX diff --git a/packages/astro/src/runtime/server/escape.ts b/packages/astro/src/runtime/server/escape.ts index 879f1e75bfb9..b7bf60c3c898 100644 --- a/packages/astro/src/runtime/server/escape.ts +++ b/packages/astro/src/runtime/server/escape.ts @@ -101,6 +101,8 @@ export function unescapeHTML( return Promise.resolve(str).then((value) => { return unescapeHTML(value); }); + } else if(str[Symbol.for('astro:slot-string')]) { + return str; } else if (Symbol.iterator in str) { return unescapeChunks(str); } else if (Symbol.asyncIterator in str || hasGetReader(str)) { diff --git a/packages/astro/test/fixtures/hydration-race/src/components/WithSlot.astro b/packages/astro/test/fixtures/hydration-race/src/components/WithSlot.astro new file mode 100644 index 000000000000..f6edb24ebbed --- /dev/null +++ b/packages/astro/test/fixtures/hydration-race/src/components/WithSlot.astro @@ -0,0 +1,16 @@ +--- +const getHtml = async () => { + if(Astro.slots.has("default")) { + let output = await Astro.slots.render("default", [{ + foo: "bar" + }]); + return output; + } else { + return ""; + } +}; + +--- + + + diff --git a/packages/astro/test/fixtures/hydration-race/src/pages/slot.astro b/packages/astro/test/fixtures/hydration-race/src/pages/slot.astro new file mode 100644 index 000000000000..7d70f561e2df --- /dev/null +++ b/packages/astro/test/fixtures/hydration-race/src/pages/slot.astro @@ -0,0 +1,34 @@ +--- +// Component Imports +import Demo from '../components/One.jsx'; +import WithSlot from '../components/WithSlot.astro'; + +// Full Astro Component Syntax: +// https://docs.astro.build/core-concepts/astro-components/ +--- + + + + + + + + + + +
+ + {(foo) => } + +
+ + diff --git a/packages/astro/test/hydration-race.test.js b/packages/astro/test/hydration-race.test.js index ac2af37232ba..00837fdd9bc3 100644 --- a/packages/astro/test/hydration-race.test.js +++ b/packages/astro/test/hydration-race.test.js @@ -27,4 +27,15 @@ describe('Hydration script ordering', async () => { assert.equal($('style').length, 1, 'hydration style added once'); assert.equal($('script').length, 1, 'only one hydration script needed'); }); + + it('Hydration script included when inside dynamic slot', async () => { + let html = await fixture.readFile('/slot/index.html'); + let $ = cheerio.load(html); + + // First, let's make sure all islands rendered + assert.equal($('astro-island').length, 1); + + // There should be 1 script + assert.equal($('script').length, 1); + }); });