Skip to content

Commit a98f6f4

Browse files
authored
Prevent body head content injection in MDX when using layout (#6779)
1 parent e0ee776 commit a98f6f4

File tree

7 files changed

+63
-0
lines changed

7 files changed

+63
-0
lines changed

.changeset/smart-files-flow.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'astro': patch
3+
'@astrojs/mdx': patch
4+
---
5+
6+
Prevent body head content injection in MDX when using layout

packages/astro/src/runtime/server/render/page.ts

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export async function renderPage(
7676
route?: RouteData | undefined
7777
): Promise<Response> {
7878
if (!isAstroComponentFactory(componentFactory)) {
79+
result._metadata.headInTree =
80+
result.componentMetadata.get((componentFactory as any).moduleId)?.containsHead ?? false;
7981
const pageProps: Record<string, any> = { ...(props ?? {}), 'server:root': true };
8082

8183
let output: ComponentIterable;

packages/integrations/mdx/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
160160
// Ensures styles and scripts are injected into a `<head>`
161161
// When a layout is not applied
162162
code += `\nContent[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
163+
code += `\nContent.moduleId = ${JSON.stringify(id)};`
163164

164165
if (command === 'dev') {
165166
// TODO: decline HMR updates until we have a stable approach

packages/integrations/mdx/test/css-head-mdx.test.js

+13
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,18 @@ describe('Head injection w/ MDX', () => {
8181
const bodyLinks = $('body link[rel=stylesheet]');
8282
expect(bodyLinks).to.have.a.lengthOf(0);
8383
});
84+
85+
it('Injection caused by delayed slots', async () => {
86+
const html = await fixture.readFile('/componentwithtext/index.html');
87+
88+
// Using cheerio here because linkedom doesn't support head tag injection
89+
const $ = cheerio.load(html);
90+
91+
const headLinks = $('head link[rel=stylesheet]');
92+
expect(headLinks).to.have.a.lengthOf(1);
93+
94+
const bodyLinks = $('body link[rel=stylesheet]');
95+
expect(bodyLinks).to.have.a.lengthOf(0);
96+
});
8497
});
8598
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
const { inlineStyle, title, display = 'horizontal' } = Astro.props;
3+
const lineEnding = display === 'horizontal' ? ', ' : '<br>';
4+
---
5+
6+
{title && <h2 set:html={title} />}
7+
<address style={inlineStyle}>
8+
<span class="name">some name</span><Fragment set:html={lineEnding} />
9+
line 1<Fragment set:html={lineEnding} />
10+
line 2<Fragment set:html={lineEnding} />
11+
line 3<Fragment set:html={lineEnding} />
12+
line 4<Fragment set:html={lineEnding} />
13+
line 5
14+
</address>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
// Extend the BaseLayout, adding space for a banner at the top of the page
3+
// after the main heading, then the detail for the actual page
4+
import ContentLayout from './ContentLayout.astro';
5+
const { frontmatter } = Astro.props;
6+
---
7+
8+
<ContentLayout>
9+
<div class="content-container">
10+
<article id="main-content" class="pad-z5 flow">
11+
<h1 set:html={frontmatter.pageHeading ? frontmatter.pageHeading : frontmatter.title} />
12+
<slot />
13+
</article>
14+
</div>
15+
</ContentLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
layout: ../layouts/DocumentLayout.astro
3+
title: blah blah
4+
---
5+
6+
import BasicBlock from '../components/BasicBlock.astro';
7+
8+
Some text for a paragraph.
9+
10+
<BasicBlock title="This causes css in wrong place." />
11+
12+
Some other text.

0 commit comments

Comments
 (0)