From 79783fc0181153a8e379d3f023422510a7467ead Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 13 Feb 2023 07:49:10 -0500 Subject: [PATCH] Fix head injection in body with slots.render() and head buffering (#6216) * Fix head injection in body with slots.render() and head buffering * Adding a changeset * An MDX test too --- .changeset/eight-cameras-itch.md | 5 +++++ packages/astro/src/runtime/server/render/common.ts | 11 ++++++++++- .../src/components/UsesSlotRender.astro | 7 +++++++ .../src/pages/with-render-slot-in-head-buffer.astro | 7 +++++++ packages/astro/test/head-injection.test.js | 8 ++++++++ packages/integrations/mdx/test/css-head-mdx.test.js | 12 ++++++++++++ .../css-head-mdx/src/components/BaseHead.astro | 11 +++++++++++ .../src/components/GenericComponent.astro | 1 + .../css-head-mdx/src/components/MDXWrapper.astro | 9 +++++++++ .../src/content/posts/using-component.mdx | 13 +++++++++++++ .../css-head-mdx/src/layouts/ContentLayout.astro | 10 ++-------- 11 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 .changeset/eight-cameras-itch.md create mode 100644 packages/astro/test/fixtures/head-injection/src/components/UsesSlotRender.astro create mode 100644 packages/astro/test/fixtures/head-injection/src/pages/with-render-slot-in-head-buffer.astro create mode 100644 packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/BaseHead.astro create mode 100644 packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/GenericComponent.astro create mode 100644 packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/MDXWrapper.astro create mode 100644 packages/integrations/mdx/test/fixtures/css-head-mdx/src/content/posts/using-component.mdx diff --git a/.changeset/eight-cameras-itch.md b/.changeset/eight-cameras-itch.md new file mode 100644 index 000000000000..4499c5a46e27 --- /dev/null +++ b/.changeset/eight-cameras-itch.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix head injection in body with slots.render() and head buffering diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts index 6bcd72cc54d4..a33ed435d87f 100644 --- a/packages/astro/src/runtime/server/render/common.ts +++ b/packages/astro/src/runtime/server/render/common.ts @@ -72,13 +72,22 @@ export function stringifyChunk(result: SSRResult, chunk: string | SlotString | R } // If the current scope is with Astro.slots.render() - case ScopeFlags.Slot: { + case ScopeFlags.Slot: + case ScopeFlags.Slot | ScopeFlags.HeadBuffer: { if (hasScopeFlag(result, ScopeFlags.RenderSlot)) { return ''; } break; } + // Nested element inside of JSX during head buffering phase + case ScopeFlags.HeadBuffer: { + if(hasScopeFlag(result, ScopeFlags.JSX | ScopeFlags.HeadBuffer)) { + return ""; + } + break; + } + // Astro.slots.render() should never render head content. case ScopeFlags.RenderSlot | ScopeFlags.Astro: case ScopeFlags.RenderSlot | ScopeFlags.Astro | ScopeFlags.JSX: diff --git a/packages/astro/test/fixtures/head-injection/src/components/UsesSlotRender.astro b/packages/astro/test/fixtures/head-injection/src/components/UsesSlotRender.astro new file mode 100644 index 000000000000..35d127cd5ef2 --- /dev/null +++ b/packages/astro/test/fixtures/head-injection/src/components/UsesSlotRender.astro @@ -0,0 +1,7 @@ +--- +import SlotRenderComponent from "./SlotRenderComponent.astro"; +--- + + +

Paragraph.

+
diff --git a/packages/astro/test/fixtures/head-injection/src/pages/with-render-slot-in-head-buffer.astro b/packages/astro/test/fixtures/head-injection/src/pages/with-render-slot-in-head-buffer.astro new file mode 100644 index 000000000000..5cd5c6261b5b --- /dev/null +++ b/packages/astro/test/fixtures/head-injection/src/pages/with-render-slot-in-head-buffer.astro @@ -0,0 +1,7 @@ +--- +import Layout from "../components/Layout.astro"; +import UsesSlotRender from "../components/UsesSlotRender.astro" +--- + + + diff --git a/packages/astro/test/head-injection.test.js b/packages/astro/test/head-injection.test.js index d06a6eed0f87..d86272712c89 100644 --- a/packages/astro/test/head-injection.test.js +++ b/packages/astro/test/head-injection.test.js @@ -50,6 +50,14 @@ describe('Head injection', () => { expect($('head link[rel=stylesheet]')).to.have.a.lengthOf(2); expect($('body link[rel=stylesheet]')).to.have.a.lengthOf(0); }); + + it('Using slots in Astro.slots.render() inside head buffering', async () => { + const html = await fixture.readFile('/with-render-slot-in-head-buffer/index.html'); + const $ = cheerio.load(html); + + expect($('head link[rel=stylesheet]')).to.have.a.lengthOf(2); + expect($('body link[rel=stylesheet]')).to.have.a.lengthOf(0); + }); }); }); }); diff --git a/packages/integrations/mdx/test/css-head-mdx.test.js b/packages/integrations/mdx/test/css-head-mdx.test.js index bb2c7c0effe5..781e4d62d51d 100644 --- a/packages/integrations/mdx/test/css-head-mdx.test.js +++ b/packages/integrations/mdx/test/css-head-mdx.test.js @@ -69,5 +69,17 @@ describe('Head injection w/ MDX', () => { const bodyLinks = $('body link[rel=stylesheet]'); expect(bodyLinks).to.have.a.lengthOf(0); }); + + it('JSX component rendering Astro children within head buffering phase', async () => { + const html = await fixture.readFile('/posts/using-component/index.html'); + // Using cheerio here because linkedom doesn't support head tag injection + const $ = cheerio.load(html); + + const headLinks = $('head link[rel=stylesheet]'); + expect(headLinks).to.have.a.lengthOf(1); + + const bodyLinks = $('body link[rel=stylesheet]'); + expect(bodyLinks).to.have.a.lengthOf(0); + }); }); }); diff --git a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/BaseHead.astro b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/BaseHead.astro new file mode 100644 index 000000000000..19f517789607 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/BaseHead.astro @@ -0,0 +1,11 @@ +--- +const { title } = Astro.props; +--- + + + + +{title} + diff --git a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/GenericComponent.astro b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/GenericComponent.astro new file mode 100644 index 000000000000..ebcd3ff35944 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/GenericComponent.astro @@ -0,0 +1 @@ +just a generic component diff --git a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/MDXWrapper.astro b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/MDXWrapper.astro new file mode 100644 index 000000000000..fbd530e1462e --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/components/MDXWrapper.astro @@ -0,0 +1,9 @@ +--- +import Component from "./GenericComponent.astro"; +--- + +
+ + + +
diff --git a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/content/posts/using-component.mdx b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/content/posts/using-component.mdx new file mode 100644 index 000000000000..fa550fb041f3 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/content/posts/using-component.mdx @@ -0,0 +1,13 @@ +--- +title: testing +--- +import MDXWrapper from "../../components/MDXWrapper.astro"; + + +

+ testing +

+
+ Intro +
+
diff --git a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/layouts/ContentLayout.astro b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/layouts/ContentLayout.astro index 7b234e86859a..e670601361bf 100644 --- a/packages/integrations/mdx/test/fixtures/css-head-mdx/src/layouts/ContentLayout.astro +++ b/packages/integrations/mdx/test/fixtures/css-head-mdx/src/layouts/ContentLayout.astro @@ -1,4 +1,5 @@ --- +import BaseHead from "../components/BaseHead.astro"; export interface Props { title: string; } @@ -9,14 +10,7 @@ const { title } = Astro.props; - - - - - {title} - +