summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/chilly-ladybugs-leave.md5
-rw-r--r--packages/astro/src/core/render/result.ts12
-rw-r--r--packages/astro/src/runtime/server/render/common.ts15
-rw-r--r--packages/astro/src/runtime/server/render/slot.ts8
-rw-r--r--packages/astro/test/astro-slots-nested.test.js6
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/components/SlotRender.astro4
-rw-r--r--packages/astro/test/fixtures/astro-slots-nested/src/pages/component-slot.astro17
7 files changed, 60 insertions, 7 deletions
diff --git a/.changeset/chilly-ladybugs-leave.md b/.changeset/chilly-ladybugs-leave.md
new file mode 100644
index 000000000..52a016ff7
--- /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 2d7c07d84..615f47bfa 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 3aac428cf..ef33ae3ee 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 5aee6dfa4..52a1d59a2 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<string> {
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 58f7153b0..9e02388ce 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 000000000..3da3fbd54
--- /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');
+---
+<Fragment set:html={content} />
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 000000000..b9a03f887
--- /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'
+---
+
+<html lang="en">
+ <head>
+ <title>Testing</title>
+ </head>
+ <body>
+ <main>
+ <SlotRender>
+ <Inner client:load />
+ </SlotRender>
+ </main>
+ </body>
+</html>