From 5abf3fbfee21876056694cc22427f3efea2cbd1c Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 28 Jun 2023 23:37:40 +0200 Subject: [PATCH] Enable react profiling option for app dir client components --- packages/next/src/build/webpack-config.ts | 34 ++++++++++----- packages/next/src/server/config-schema.ts | 3 ++ packages/next/src/server/config-shared.ts | 7 ++++ packages/next/taskfile.js | 1 - .../react-profiling-mode/pages/index.js | 2 +- .../react-profiling-mode/test/index.test.js | 41 ++++++++++++++----- 6 files changed, 65 insertions(+), 23 deletions(-) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 31ed619c8b27a0..43a13398cf28af 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -406,9 +406,17 @@ export function getDefineEnv({ } } +function getReactProfilingInProduction() { + return { + 'react-dom$': 'react-dom/profiling', + 'scheduler/tracing': 'scheduler/tracing-profiling', + } +} + function createRSCAliases( bundledReactChannel: string, opts: { + reactProductionProfiling: boolean reactSharedSubset: boolean reactDomServerRenderingStub: boolean reactServerCondition?: boolean @@ -455,6 +463,15 @@ function createRSCAliases( } } + if (opts.reactProductionProfiling) { + alias[ + 'react-dom$' + ] = `next/dist/compiled/react-dom${bundledReactChannel}/profiling` + alias[ + 'scheduler/tracing' + ] = `next/dist/compiled/scheduler${bundledReactChannel}/tracing-profiling` + } + return alias } @@ -998,15 +1015,6 @@ export default async function getBaseWebpackConfig( } as ClientEntries) : undefined - function getReactProfilingInProduction() { - if (reactProductionProfiling) { - return { - 'react-dom$': 'react-dom/profiling', - 'scheduler/tracing': 'scheduler/tracing-profiling', - } - } - } - // tell webpack where to look for _app and _document // using aliases to allow falling back to the default // version when removed or not present @@ -1145,7 +1153,7 @@ export default async function getBaseWebpackConfig( [ROOT_DIR_ALIAS]: dir, [DOT_NEXT_ALIAS]: distDir, ...(isClient || isEdgeServer ? getOptimizedAliases() : {}), - ...getReactProfilingInProduction(), + ...(reactProductionProfiling ? getReactProfilingInProduction() : {}), [RSC_ACTION_VALIDATE_ALIAS]: 'next/dist/build/webpack/loaders/next-flight-loader/action-validate', @@ -1933,6 +1941,7 @@ export default async function getBaseWebpackConfig( ...createRSCAliases(bundledReactChannel, { reactSharedSubset: false, reactDomServerRenderingStub: false, + reactProductionProfiling, }), }, }, @@ -1965,6 +1974,8 @@ export default async function getBaseWebpackConfig( reactSharedSubset: true, reactDomServerRenderingStub: true, reactServerCondition: true, + // No server components profiling + reactProductionProfiling, }), }, }, @@ -2028,6 +2039,7 @@ export default async function getBaseWebpackConfig( reactSharedSubset: true, reactDomServerRenderingStub: true, reactServerCondition: true, + reactProductionProfiling, }), }, }, @@ -2041,6 +2053,7 @@ export default async function getBaseWebpackConfig( reactSharedSubset: false, reactDomServerRenderingStub: true, reactServerCondition: false, + reactProductionProfiling, }), }, }, @@ -2057,6 +2070,7 @@ export default async function getBaseWebpackConfig( reactSharedSubset: false, reactDomServerRenderingStub: false, reactServerCondition: false, + reactProductionProfiling, }), }, }, diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 1439550ee4e30c..49dbc1a53de19a 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -743,6 +743,9 @@ const configSchema = { publicRuntimeConfig: { type: 'object', }, + reactProductionProfiling: { + type: 'boolean', + }, reactStrictMode: { type: 'boolean', }, diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 00b56e469a0b05..0fea822abd098c 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -507,6 +507,12 @@ export interface NextConfig extends Record { */ optimizeFonts?: boolean + /** + * Enable react profiling in production + * + */ + reactProductionProfiling?: boolean + /** * The Next.js runtime is Strict Mode-compliant. * @@ -670,6 +676,7 @@ export const defaultConfig: NextConfig = { excludeDefaultMomentLocales: true, serverRuntimeConfig: {}, publicRuntimeConfig: {}, + reactProductionProfiling: false, reactStrictMode: false, httpAgentOptions: { keepAlive: true, diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 47390389a00185..290c951b8c601a 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -1760,7 +1760,6 @@ export async function copy_vendor_react(task_) { 'static.browser.js', 'unstable_testing.js', 'test-utils.js', - 'profiling.js', 'server.bun.js', 'cjs/react-dom-server.bun.development.js', 'cjs/react-dom-server.bun.production.min.js', diff --git a/test/integration/react-profiling-mode/pages/index.js b/test/integration/react-profiling-mode/pages/index.js index f8a1751572139e..35d12375f088a0 100644 --- a/test/integration/react-profiling-mode/pages/index.js +++ b/test/integration/react-profiling-mode/pages/index.js @@ -9,7 +9,7 @@ const Index = () => { window.profileResults.push(res) }} > -

hello world

+

hello pages

) } diff --git a/test/integration/react-profiling-mode/test/index.test.js b/test/integration/react-profiling-mode/test/index.test.js index d868cc3ddb62e8..200530450970e3 100644 --- a/test/integration/react-profiling-mode/test/index.test.js +++ b/test/integration/react-profiling-mode/test/index.test.js @@ -14,11 +14,22 @@ let app describe('React Profiling Mode', () => { describe('without config enabled', () => { beforeAll(async () => { + await fs.remove(nextConfig) await nextBuild(appDir) appPort = await findPort() app = await nextStart(appDir, appPort) }) - afterAll(() => killApp(app)) + afterAll(async () => { + await fs.writeFile( + nextConfig, + ` + module.exports = { + reactProductionProfiling: true + } + ` + ) + await killApp(app) + }) it('should not have used the react-dom profiling bundle', async () => { const browser = await webdriver(appPort, '/') @@ -30,29 +41,37 @@ describe('React Profiling Mode', () => { describe('with config enabled', () => { beforeAll(async () => { - await fs.writeFile( - nextConfig, - ` - module.exports = { - reactProductionProfiling: true - } - ` - ) await nextBuild(appDir, ['--profile']) appPort = await findPort() app = await nextStart(appDir, appPort) }) afterAll(async () => { - await fs.remove(nextConfig) await killApp(app) }) - it('should have used the react-dom profiling bundle', async () => { + it('should have used the react-dom profiling bundle for pages', async () => { const browser = await webdriver(appPort, '/') const results = await browser.eval('window.profileResults') expect(results.length).toBe(1) expect(results[0] && results[0][0]).toBe('hello') }) + + it('should have used the react-dom profiling bundle for client component', async () => { + const browser = await webdriver(appPort, '/client') + const results = await browser.eval('window.profileResults') + + expect(results.length).toBe(1) + expect(results[0] && results[0][0]).toBe('hello-app-client') + }) + + it('should have used the react-dom profiling bundle for server component', async () => { + // Can't test react Profiler API in server components but make sure rendering works + const browser = await webdriver(appPort, '/server') + + expect(await browser.waitForElementByCss('p').text()).toBe( + 'hello app server' + ) + }) }) })