chore: show large data warning once per page on prod (#46323)

<!--
Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:
-->

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Related

* Closes https://github.com/vercel/next.js/pull/39146 - PR abandoned.

## Details

I was having the same issue at work, as a workaround, we've changed the
`largePageDataBytes` setting as advised but we'd like to keep the
warning ideally. It's something we need to address, but just don't want
to spam our log aggregators while the large data issue isn't resolved.

I believe I've more or less copied what was in the original PR, some
small differences:
* I use `Set` instead of `Map`, please let me know if there is an
advantage to using Map!
* Just to keep code a bit tidier (subjective) put an early return
instead of nesting all the code in an if.
* Added a test to verify only one log appears even when the page is
accessed twice [as requested
here](https://github.com/vercel/next.js/pull/39146#pullrequestreview-1064486985).
This commit is contained in:
Seth Falco 2023-02-25 21:29:59 +01:00 committed by GitHub
parent d9776ccc17
commit adefdd2aaa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 0 deletions

View file

@ -41,6 +41,9 @@ type HeadHTMLProps = React.DetailedHTMLProps<
type HeadProps = OriginProps & HeadHTMLProps
/** Set of pages that have triggered a large data warning on production mode. */
const largePageDataWarnings = new Set<string>()
function getDocumentFiles(
buildManifest: BuildManifest,
pathname: string,
@ -998,6 +1001,11 @@ export class NextScript extends React.Component<OriginProps> {
const { __NEXT_DATA__, largePageDataBytes } = context
try {
const data = JSON.stringify(__NEXT_DATA__)
if (largePageDataWarnings.has(__NEXT_DATA__.page)) {
return htmlEscapeJsonString(data)
}
const bytes =
process.env.NEXT_RUNTIME === 'edge'
? new TextEncoder().encode(data).buffer.byteLength
@ -1005,6 +1013,10 @@ export class NextScript extends React.Component<OriginProps> {
const prettyBytes = require('../lib/pretty-bytes').default
if (largePageDataBytes && bytes > largePageDataBytes) {
if (process.env.NODE_ENV === 'production') {
largePageDataWarnings.add(__NEXT_DATA__.page)
}
console.warn(
`Warning: data for page "${__NEXT_DATA__.page}"${
__NEXT_DATA__.page === context.dangerousAsPath

View file

@ -967,6 +967,39 @@ describe('Prerender', () => {
)
})
if ((global as any).isNextDev) {
it('should show warning every time page with large amount of page data is returned', async () => {
await renderViaHTTP(next.url, '/large-page-data-ssr')
await check(
() => next.cliOutput,
/Warning: data for page "\/large-page-data-ssr" is 256 kB which exceeds the threshold of 128 kB, this amount of data can reduce performance/
)
const outputIndex = next.cliOutput.length
await renderViaHTTP(next.url, '/large-page-data-ssr')
await check(
() => next.cliOutput.slice(outputIndex),
/Warning: data for page "\/large-page-data-ssr" is 256 kB which exceeds the threshold of 128 kB, this amount of data can reduce performance/
)
})
}
if ((global as any).isNextStart) {
it('should only show warning once per page when large amount of page data is returned', async () => {
await renderViaHTTP(next.url, '/large-page-data-ssr')
await check(
() => next.cliOutput,
/Warning: data for page "\/large-page-data-ssr" is 256 kB which exceeds the threshold of 128 kB, this amount of data can reduce performance/
)
const outputIndex = next.cliOutput.length
await renderViaHTTP(next.url, '/large-page-data-ssr')
expect(next.cliOutput.slice(outputIndex)).not.toInclude(
'Warning: data for page'
)
})
}
if ((global as any).isNextDev) {
it('should not show warning from url prop being returned', async () => {
const urlPropPage = 'pages/url-prop.js'
@ -1483,6 +1516,12 @@ describe('Prerender', () => {
)}\\/large-page-data.json$`,
page: '/large-page-data',
},
{
dataRouteRegex: `^\\/_next\\/data\\/${escapeRegex(
next.buildId
)}\\/large-page-data-ssr.json$`,
page: '/large-page-data-ssr',
},
{
namedDataRouteRegex: `^/_next/data/${escapeRegex(
next.buildId

View file

@ -0,0 +1,25 @@
import React from 'react'
import Link from 'next/link'
export function getServerSideProps() {
return {
props: {
lotsOfData: new Array(256 * 1000).fill('a').join(''),
},
}
}
export default (props) => {
return (
<>
<p>lots of data returned</p>
<Link href="/" id="home">
to home
</Link>
<br />
<Link href="/another" id="another">
to another
</Link>
</>
)
}