Skip to content

Commit

Permalink
Ensure that maybeRenderHead runs last (#3821)
Browse files Browse the repository at this point in the history
* Ensure that maybeRenderHead runs last

* Adds a changeset

* Make work with MDX
  • Loading branch information
matthewp authored Jul 6, 2022
1 parent 5ac0f78 commit c2165c3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/hip-months-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix for putting the <head> into its own component
20 changes: 12 additions & 8 deletions packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,6 @@ export async function renderPage(
children: any,
streaming: boolean
): Promise<Response> {
let iterable: AsyncIterable<any>;
if (!componentFactory.isAstroComponentFactory) {
const pageProps: Record<string, any> = { ...(props ?? {}), 'server:root': true };
const output = await renderComponent(
Expand All @@ -719,12 +718,17 @@ export async function renderPage(
);
let html = output.toString();
if (!/<!doctype html/i.test(html)) {
html = `<!DOCTYPE html>\n${await maybeRenderHead(result)}${html}`;
let rest = html;
html = `<!DOCTYPE html>`;
for await(let chunk of maybeRenderHead(result)) {
html += chunk;
}
html += rest;
}
return new Response(html, {
headers: new Headers([
['Content-Type', 'text/html; charset=utf-8'],
['Content-Length', `${Buffer.byteLength(html, 'utf-8')}`],
['Content-Length', Buffer.byteLength(html, 'utf-8').toString()],
]),
});
}
Expand Down Expand Up @@ -769,7 +773,7 @@ export async function renderPage(
i++;
}
const bytes = encoder.encode(body);
headers.set('Content-Length', `${bytes.byteLength}`);
headers.set('Content-Length', bytes.byteLength.toString());
}

let response = createResponse(body, { ...init, headers });
Expand All @@ -789,7 +793,7 @@ const uniqueElements = (item: any, index: number, all: any[]) => {
};

const alreadyHeadRenderedResults = new WeakSet<SSRResult>();
export async function renderHead(result: SSRResult): Promise<string> {
export function renderHead(result: SSRResult): Promise<string> {
alreadyHeadRenderedResults.add(result);
const styles = Array.from(result.styles)
.filter(uniqueElements)
Expand All @@ -811,11 +815,11 @@ export async function renderHead(result: SSRResult): Promise<string> {
// This accomodates the fact that using a <head> is optional in Astro, so this
// is called before a component's first non-head HTML element. If the head was
// already injected it is a noop.
export function maybeRenderHead(result: SSRResult): string | Promise<string> {
export async function* maybeRenderHead(result: SSRResult): AsyncIterable<string> {
if (alreadyHeadRenderedResults.has(result)) {
return '';
return;
}
return renderHead(result);
yield renderHead(result);
}

export async function* renderAstroComponent(
Expand Down
23 changes: 23 additions & 0 deletions packages/astro/test/astro-head.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';

describe('Head in its own component', () => {
let fixture;

before(async () => {
fixture = await loadFixture({
root: './fixtures/astro-head/',
site: 'https://mysite.dev/',
base: '/blog',
});
await fixture.build();
});

it('Styles are appended to the head and not the body', async () => {
let html = await fixture.readFile('/head-own-component/index.html');
let $ = cheerio.load(html);
expect($('link[rel=stylesheet]')).to.have.a.lengthOf(1, 'one stylesheet overall');
expect($('head link[rel=stylesheet]')).to.have.a.lengthOf(1, 'stylesheet is in the head');
});
});
11 changes: 11 additions & 0 deletions packages/astro/test/fixtures/astro-head/src/components/Head.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
// Head.astro
const { title } = Astro.props;
---

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<title>{title}</title>
</head>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
// Layout.astro
import Head from "../components/Head.astro";
---

<!DOCTYPE html>
<html lang="en">
<Head title="title"/>
<body>
<h1>Title Here</h1>
<style>
body {
background: green;
}
</style>
</body>

0 comments on commit c2165c3

Please sign in to comment.