-
Notifications
You must be signed in to change notification settings - Fork 26.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ppr] Configuration for max react headers length (#67715)
### What? This exposes a new `reactMaxHeadersLength` config option for `next.config.js`: ```js module.exports = { reactMaxHeadersLength: 1000, } ``` That allows configuration of the maximum value of all the headers generated from React. Currently only added when the experimental partial prerendering (PPR) feature is enabled, this today only affects the size of the `Link` header that is emitted which contains preloads for assets like fonts. This also bumps the default value from 600 to 6000. ### Why? Some proxies may have differing support for max header sizes, so this was added as a configuration option to allow users to better control the output experience in these cases. At the time of writing, most proxies support a maximum of 8k bytes in the header, which is above the default 6k, allowing for other headers written by Next.js. --------- Co-authored-by: Sam Ko <[email protected]>
- Loading branch information
Showing
12 changed files
with
138 additions
and
2 deletions.
There are no files selected for viewing
16 changes: 16 additions & 0 deletions
16
docs/02-app/02-api-reference/05-next-config-js/reactMaxHeadersLength.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--- | ||
title: reactMaxHeadersLength | ||
description: The maximum length of the headers that are emitted by React and added to the response. | ||
--- | ||
|
||
During static rendering, React can emit headers that can be added to the response. These can be used to improve performance by allowing the browser to preload resources like fonts, scripts, and stylesheets. The default value is `6000`, but you can override this value by configuring the `reactMaxHeadersLength` option in `next.config.js`: | ||
|
||
```js filename="next.config.js" | ||
module.exports = { | ||
reactMaxHeadersLength: 1000, | ||
} | ||
``` | ||
|
||
> **Good to know**: This option is only available in App Router. | ||
Depending on the type of proxy between the browser and the server, the headers can be truncated. For example, if you are using a reverse proxy that doesn't support long headers, you should set a lower value to ensure that the headers are not truncated. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { ReactNode } from 'react' | ||
import { preload } from 'react-dom' | ||
|
||
export default function Root({ children }: { children: ReactNode }) { | ||
// Each of these preloads will emit a link header that will consist of about | ||
// 105 characters. | ||
for (let i = 0; i < 100; i++) { | ||
preload( | ||
'/?q=some+string+that+spans+lots+of+characters&i=' + | ||
String(i).padStart(2, '0'), | ||
{ | ||
as: 'font', | ||
type: 'font/woff2', | ||
crossOrigin: 'anonymous', | ||
} | ||
) | ||
} | ||
return ( | ||
<html> | ||
<body>{children}</body> | ||
</html> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <p>hello world</p> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* @type {import('next').NextConfig} | ||
*/ | ||
const nextConfig = { | ||
reactMaxHeadersLength: process.env.TEST_REACT_MAX_HEADERS_LENGTH | ||
? parseInt(process.env.TEST_REACT_MAX_HEADERS_LENGTH) | ||
: undefined, | ||
experimental: { | ||
// Emitting Link headers currently requires the experimental PPR feature. | ||
ppr: true, | ||
}, | ||
} | ||
|
||
module.exports = nextConfig |
60 changes: 60 additions & 0 deletions
60
test/e2e/app-dir/react-max-headers-length/react-max-headers-length.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { nextTestSetup } from 'e2e-utils' | ||
|
||
const LINK_HEADER_SIZE = 111 | ||
|
||
/** | ||
* Calculates the minimum header length that will be emitted by the server. This | ||
* is calculated by taking the maximum header length and dividing it by the | ||
* average header size including joining `, ` characters. | ||
* | ||
* @param maxLength the maximum header length | ||
* @returns the minimum header length | ||
*/ | ||
function calculateMinHeaderLength(maxLength) { | ||
const averageHeaderSize = LINK_HEADER_SIZE + 2 | ||
return Math.floor(maxLength / averageHeaderSize) * averageHeaderSize - 2 | ||
} | ||
|
||
describe('react-max-headers-length', () => { | ||
describe.each([0, 400, undefined, 10000])( | ||
'reactMaxHeadersLength = %s', | ||
(reactMaxHeadersLength) => { | ||
const env: Record<string, string> = {} | ||
if (typeof reactMaxHeadersLength === 'number') { | ||
env.TEST_REACT_MAX_HEADERS_LENGTH = reactMaxHeadersLength.toString() | ||
} | ||
|
||
const { next } = nextTestSetup({ files: __dirname, env }) | ||
|
||
it('should respect reactMaxHeadersLength', async () => { | ||
const res = await next.fetch('/') | ||
|
||
// React currently only sets the `Link` header, so we should check to | ||
// see that the length of the header has respected the configured | ||
// value. | ||
const header = res.headers.get('Link') | ||
if (reactMaxHeadersLength === undefined) { | ||
// This is the default case. | ||
expect(header).toBeString() | ||
|
||
expect(header.length).toBeGreaterThanOrEqual( | ||
calculateMinHeaderLength(6000) | ||
) | ||
expect(header.length).toBeLessThanOrEqual(6000) | ||
} else if (reactMaxHeadersLength === 0) { | ||
// This is the case where the header is not emitted. | ||
expect(header).toBeNull() | ||
} else if (typeof reactMaxHeadersLength === 'number') { | ||
// This is the case where the header is emitted and the length is | ||
// respected. | ||
expect(header).toBeString() | ||
|
||
expect(header.length).toBeGreaterThanOrEqual( | ||
calculateMinHeaderLength(reactMaxHeadersLength) | ||
) | ||
expect(header.length).toBeLessThanOrEqual(reactMaxHeadersLength) | ||
} | ||
}) | ||
} | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters