From 39302141b5ea3a1e9a55af906129a44675337cf9 Mon Sep 17 00:00:00 2001 From: Shyam Gupta <38554977+sshyam-gupta@users.noreply.github.com> Date: Sun, 29 May 2022 07:09:48 +0530 Subject: [PATCH] Show warning during build if page is returning a large amount of data (#37264) ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using fixes #33829 - [x] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com> --- packages/next/export/index.ts | 1 + packages/next/pages/_document.tsx | 22 ++++++++++----------- packages/next/server/base-server.ts | 2 ++ packages/next/server/config-shared.ts | 2 ++ packages/next/server/render.tsx | 2 ++ packages/next/shared/lib/html-context.ts | 1 + test/e2e/prerender.test.ts | 16 +++++++-------- test/e2e/prerender/pages/large-page-data.js | 2 +- 8 files changed, 28 insertions(+), 20 deletions(-) diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 79a52449b37f3..7166bfeac1385 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -385,6 +385,7 @@ export default async function exportApp( nextScriptWorkers: nextConfig.experimental.nextScriptWorkers, optimizeFonts: nextConfig.optimizeFonts, reactRoot: nextConfig.experimental.reactRoot || false, + largePageDataBytes: nextConfig.experimental.largePageDataBytes, } const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index f7f8abaac3852..c639698f4b66b 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -946,20 +946,20 @@ export class NextScript extends Component { } static getInlineScriptSource(context: Readonly): string { - const { __NEXT_DATA__ } = context + const { __NEXT_DATA__, largePageDataBytes } = context try { const data = JSON.stringify(__NEXT_DATA__) + const bytes = Buffer.from(data).byteLength + const prettyBytes = require('../lib/pretty-bytes').default - if (process.env.NODE_ENV === 'development') { - const bytes = Buffer.from(data).byteLength - const prettyBytes = require('../lib/pretty-bytes').default - if (bytes > 128 * 1000) { - console.warn( - `Warning: data for page "${__NEXT_DATA__.page}" is ${prettyBytes( - bytes - )}, this amount of data can reduce performance.\nSee more info here: https://nextjs.org/docs/messages/large-page-data` - ) - } + if (largePageDataBytes && bytes > largePageDataBytes) { + console.warn( + `Warning: data for page "${__NEXT_DATA__.page}" is ${prettyBytes( + bytes + )} which exceeds the threshold of ${prettyBytes( + largePageDataBytes + )}, this amount of data can reduce performance.\nSee more info here: https://nextjs.org/docs/messages/large-page-data` + ) } return htmlEscapeJsonString(data) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 77fdc077da26d..17dae9483817a 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -177,6 +177,7 @@ export default abstract class Server { renderServerComponentData?: boolean serverComponentProps?: any reactRoot: boolean + largePageDataBytes?: number } protected serverOptions: ServerOptions private incrementalCache: IncrementalCache @@ -327,6 +328,7 @@ export default abstract class Server { ? this.nextConfig.crossOrigin : undefined, reactRoot: this.nextConfig.experimental.reactRoot === true, + largePageDataBytes: this.nextConfig.experimental.largePageDataBytes, } // Only the `publicRuntimeConfig` key is exposed to the client side diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index 756dd7c5a4570..94393d3eb7a20 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -135,6 +135,7 @@ export interface ExperimentalConfig { swcTraceProfiling?: boolean forceSwcTransforms?: boolean swcPlugins?: Array<[string, Record]> + largePageDataBytes?: number } /** @@ -516,6 +517,7 @@ export const defaultConfig: NextConfig = { remotePatterns: [], }, forceSwcTransforms: false, + largePageDataBytes: 128 * 1000, // 128KB by default }, } diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index ac44868ed2552..8f0431f442ff1 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -243,6 +243,7 @@ export type RenderOptsPartial = { crossOrigin?: string images: ImageConfigComplete reactRoot: boolean + largePageDataBytes?: number } export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial @@ -1562,6 +1563,7 @@ export async function renderToHTML( optimizeFonts: renderOpts.optimizeFonts, nextScriptWorkers: renderOpts.nextScriptWorkers, runtime: globalRuntime, + largePageDataBytes: renderOpts.largePageDataBytes, } const document = ( diff --git a/packages/next/shared/lib/html-context.ts b/packages/next/shared/lib/html-context.ts index b069fca0f49f9..38f881713f2f2 100644 --- a/packages/next/shared/lib/html-context.ts +++ b/packages/next/shared/lib/html-context.ts @@ -39,6 +39,7 @@ export type HtmlProps = { nextScriptWorkers?: boolean runtime?: 'edge' | 'nodejs' hasConcurrentFeatures?: boolean + largePageDataBytes?: number } export const HtmlContext = createContext(null as any) diff --git a/test/e2e/prerender.test.ts b/test/e2e/prerender.test.ts index 02e39a2566885..813fa50b0e4f2 100644 --- a/test/e2e/prerender.test.ts +++ b/test/e2e/prerender.test.ts @@ -942,15 +942,15 @@ describe('Prerender', () => { }) }) - if ((global as any).isNextDev) { - it('should show warning when large amount of page data is returned', async () => { - await renderViaHTTP(next.url, '/large-page-data') - await check( - () => next.cliOutput, - /Warning: data for page "\/large-page-data" is 128 kB, this amount of data can reduce performance/ - ) - }) + it('should show warning when large amount of page data is returned', async () => { + await renderViaHTTP(next.url, '/large-page-data') + await check( + () => next.cliOutput, + /Warning: data for page "\/large-page-data" is 256 kB which exceeds the threshold of 128 kB, this amount of data can reduce performance/ + ) + }) + if ((global as any).isNextDev) { it('should not show warning from url prop being returned', async () => { const urlPropPage = 'pages/url-prop.js' await next.patchFile( diff --git a/test/e2e/prerender/pages/large-page-data.js b/test/e2e/prerender/pages/large-page-data.js index 5293c5669cd50..41cb66471a92d 100644 --- a/test/e2e/prerender/pages/large-page-data.js +++ b/test/e2e/prerender/pages/large-page-data.js @@ -4,7 +4,7 @@ import Link from 'next/link' export async function getStaticProps({ params }) { return { props: { - lotsOfData: new Array(128 * 1000).fill('a').join(''), + lotsOfData: new Array(256 * 1000).fill('a').join(''), }, revalidate: false, }