From 88c1bbe3a71f85e92f42f13d0f310c6b2a264ade Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Tue, 8 Nov 2022 12:15:32 -0500 Subject: [PATCH] Ensure astro-island scripts render when using Astro.slots.render (#5326) * Ensure astro-island scripts render when using Astro.slots.render * Adding a changeset --- .changeset/chilly-ladybugs-leave.md | 5 +++++ packages/astro/src/core/render/result.ts | 12 ++++++------ .../astro/src/runtime/server/render/common.ts | 15 ++++++++++++++- .../astro/src/runtime/server/render/slot.ts | 8 ++++++++ packages/astro/test/astro-slots-nested.test.js | 6 ++++++ .../src/components/SlotRender.astro | 4 ++++ .../src/pages/component-slot.astro | 17 +++++++++++++++++ 7 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 .changeset/chilly-ladybugs-leave.md create mode 100644 packages/astro/test/fixtures/astro-slots-nested/src/components/SlotRender.astro create mode 100644 packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro diff --git a/.changeset/chilly-ladybugs-leave.md b/.changeset/chilly-ladybugs-leave.md new file mode 100644 index 000000000000..52a016ff7409 --- /dev/null +++ b/.changeset/chilly-ladybugs-leave.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix omitted island hydration scripts in slots diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index 2d7c07d84eef..615f47bfafdf 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -10,7 +10,7 @@ import type { SSRLoadedRenderer, SSRResult, } from '../../@types/astro'; -import { renderSlot } from '../../runtime/server/index.js'; +import { renderSlot, stringifyChunk } from '../../runtime/server/index.js'; import { renderJSX } from '../../runtime/server/jsx.js'; import { AstroCookies } from '../cookies/index.js'; import { LogOptions, warn } from '../logger/core.js'; @@ -118,11 +118,11 @@ class Slots { } } } - const content = await renderSlot(this.#result, this.#slots[name]).then((res) => - res != null ? String(res) : res - ); - if (cacheable) this.#cache.set(name, content); - return content; + const content = await renderSlot(this.#result, this.#slots[name]); + const outHTML = stringifyChunk(this.#result, content); + + if (cacheable) this.#cache.set(name, outHTML); + return outHTML; } } diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts index 3aac428cf747..ef33ae3eeac0 100644 --- a/packages/astro/src/runtime/server/render/common.ts +++ b/packages/astro/src/runtime/server/render/common.ts @@ -8,6 +8,7 @@ import { getPrescripts, PrescriptType, } from '../scripts.js'; +import { isSlotString, type SlotString } from './slot.js'; export const Fragment = Symbol.for('astro:fragment'); export const Renderer = Symbol.for('astro:renderer'); @@ -18,7 +19,7 @@ export const decoder = new TextDecoder(); // Rendering produces either marked strings of HTML or instructions for hydration. // These directive instructions bubble all the way up to renderPage so that we // can ensure they are added only once, and as soon as possible. -export function stringifyChunk(result: SSRResult, chunk: string | RenderInstruction) { +export function stringifyChunk(result: SSRResult, chunk: string | SlotString | RenderInstruction) { switch ((chunk as any).type) { case 'directive': { const { hydration } = chunk as RenderInstruction; @@ -39,6 +40,18 @@ export function stringifyChunk(result: SSRResult, chunk: string | RenderInstruct } } default: { + if(isSlotString(chunk as string)) { + let out = ''; + const c = (chunk as SlotString); + if(c.instructions) { + for(const instr of c.instructions) { + out += stringifyChunk(result, instr); + } + } + out += chunk.toString(); + return out; + } + return chunk.toString(); } } diff --git a/packages/astro/src/runtime/server/render/slot.ts b/packages/astro/src/runtime/server/render/slot.ts index 5aee6dfa4101..52a1d59a259a 100644 --- a/packages/astro/src/runtime/server/render/slot.ts +++ b/packages/astro/src/runtime/server/render/slot.ts @@ -4,14 +4,22 @@ import type { RenderInstruction } from './types.js'; import { HTMLString, markHTMLString } from '../escape.js'; import { renderChild } from './any.js'; +const slotString = Symbol.for('astro:slot-string'); + export class SlotString extends HTMLString { public instructions: null | RenderInstruction[]; + public [slotString]: boolean; constructor(content: string, instructions: null | RenderInstruction[]) { super(content); this.instructions = instructions; + this[slotString] = true; } } +export function isSlotString(str: string): str is any { + return !!(str as any)[slotString]; +} + export async function renderSlot(_result: any, slotted: string, fallback?: any): Promise { if (slotted) { let iterator = renderChild(slotted); diff --git a/packages/astro/test/astro-slots-nested.test.js b/packages/astro/test/astro-slots-nested.test.js index 58f7153b04d4..9e02388cea11 100644 --- a/packages/astro/test/astro-slots-nested.test.js +++ b/packages/astro/test/astro-slots-nested.test.js @@ -17,4 +17,10 @@ describe('Nested Slots', () => { const scriptInTemplate = $($('template')[0].children[0]).find('script'); expect(scriptInTemplate).to.have.a.lengthOf(0, 'script defined outside of the inner template'); }); + + it('Slots rendered via Astro.slots.render have the hydration script', async () => { + const html = await fixture.readFile('/component-slot/index.html'); + const $ = cheerio.load(html); + expect($('script')).to.have.a.lengthOf(1, 'script rendered'); + }); }); diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/components/SlotRender.astro b/packages/astro/test/fixtures/astro-slots-nested/src/components/SlotRender.astro new file mode 100644 index 000000000000..3da3fbd54218 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots-nested/src/components/SlotRender.astro @@ -0,0 +1,4 @@ +--- +const content = await Astro.slots.render('default'); +--- + diff --git a/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro b/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro new file mode 100644 index 000000000000..b9a03f887eb4 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro @@ -0,0 +1,17 @@ +--- +import SlotRender from '../components/SlotRender.astro' +import Inner from '../components/Inner' +--- + + + + Testing + + +
+ + + +
+ +