diff --git a/.changeset/dirty-boats-suffer.md b/.changeset/dirty-boats-suffer.md new file mode 100644 index 0000000000..9ca1d994a6 --- /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 cc7fa219e9..1e6f6f35a1 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 879f1e75bf..b7bf60c3c8 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 0000000000..f6edb24ebb --- /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 0000000000..7d70f561e2 --- /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 ac2af37232..00837fdd9b 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); + }); });