Skip to content

Commit 482fccb

Browse files
Andaristhuozhi
andauthored
Adding head element checking for root layout (#43597)
### Update We removed the `<head>` element checking for root layout in #41621. Since we also need `<head>` for preload in the future, and also css-in-js will require that. We're adding back the `head` element checking to make sure user always provide valid root layout including it. ### Issue An issue was reported [here](mui/material-ui#34905 (comment)) that the Emotion/MUI site was suffering from FOUC. After an inspection, I noticed that the SSRed HTML didn't contain the inserted styles at all - despite them being inserted through `useServerInsertedHTML`. I managed to debug it down and discovered that their layout was missing `<head></head>` and thus the stream transformer skipped the insertion altogether cause of this check: https://github.com/vercel/next.js/blob/fbc98abab31a54dbc2b6c88a064b579a10f34871/packages/next/server/node-web-streams-helper.ts#L177-L183 I've figured that at the very least we could surface this as a console error in development to nudge the user to fix the missing `<head/>` cc @huozhi Co-authored-by: Jiachi Liu <[email protected]>
1 parent 166e5fb commit 482fccb

File tree

4 files changed

+16
-8
lines changed

4 files changed

+16
-8
lines changed

packages/next/client/components/react-dev-overlay/internal/container/RootLayoutError.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type RootLayoutErrorProps = { missingTags: string[] }
1414
export const RootLayoutError: React.FC<RootLayoutErrorProps> =
1515
function BuildError({ missingTags }) {
1616
const message =
17-
'Please make sure to include the following tags in your root layout: <html>, <body>.\n\n' +
17+
'Please make sure to include the following tags in your root layout: <html>, <head>, <body>.\n\n' +
1818
`Missing required root layout tag${
1919
missingTags.length === 1 ? '' : 's'
2020
}: ` +

packages/next/server/node-web-streams-helper.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,19 @@ export function createRootLayoutValidatorStream(
288288
getTree: () => FlightRouterState
289289
): TransformStream<Uint8Array, Uint8Array> {
290290
let foundHtml = false
291+
let foundHead = false
291292
let foundBody = false
292293

293294
return new TransformStream({
294295
async transform(chunk, controller) {
295-
if (!foundHtml || !foundBody) {
296+
if (!foundHtml || !foundHead || !foundBody) {
296297
const content = decodeText(chunk)
297298
if (!foundHtml && content.includes('<html')) {
298299
foundHtml = true
299300
}
301+
if (!foundHead && content.includes('<head')) {
302+
foundHead = true
303+
}
300304
if (!foundBody && content.includes('<body')) {
301305
foundBody = true
302306
}
@@ -306,6 +310,7 @@ export function createRootLayoutValidatorStream(
306310
flush(controller) {
307311
const missingTags = [
308312
foundHtml ? null : 'html',
313+
foundHead ? null : 'head',
309314
foundBody ? null : 'body',
310315
].filter(nonNullable)
311316

test/e2e/app-dir/root-layout.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ describe('app-dir root layout', () => {
4040

4141
expect(await hasRedbox(browser, true)).toBe(true)
4242
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
43-
"Please make sure to include the following tags in your root layout: <html>, <body>.
43+
"Please make sure to include the following tags in your root layout: <html>, <head>, <body>.
4444
45-
Missing required root layout tags: html, body"
45+
Missing required root layout tags: html, head, body"
4646
`)
4747
})
4848

@@ -54,9 +54,9 @@ describe('app-dir root layout', () => {
5454

5555
expect(await hasRedbox(browser, true)).toBe(true)
5656
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
57-
"Please make sure to include the following tags in your root layout: <html>, <body>.
57+
"Please make sure to include the following tags in your root layout: <html>, <head>, <body>.
5858
59-
Missing required root layout tags: html, body"
59+
Missing required root layout tags: html, head, body"
6060
`)
6161
})
6262

@@ -67,9 +67,9 @@ describe('app-dir root layout', () => {
6767

6868
expect(await hasRedbox(browser, true)).toBe(true)
6969
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
70-
"Please make sure to include the following tags in your root layout: <html>, <body>.
70+
"Please make sure to include the following tags in your root layout: <html>, <head>, <body>.
7171
72-
Missing required root layout tags: html, body"
72+
Missing required root layout tags: html, head, body"
7373
`)
7474
})
7575
})

test/e2e/app-dir/root-layout/app/(required-tags)/has-tags/layout.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ export const revalidate = 0
44
export default function Root({ children }) {
55
return (
66
<html>
7+
<head>
8+
<title>Hello World</title>
9+
</head>
710
<body>{children}</body>
811
</html>
912
)

0 commit comments

Comments
 (0)