From af545a5daee16521c17b4378cf597c003a0bde82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 31 Jul 2023 11:45:07 +0200 Subject: [PATCH 1/6] fix: enable React Strict Mode by default --- packages/next/src/server/config-shared.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index a3ecfe752864a..db30e8b20cf96 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -682,7 +682,7 @@ export const defaultConfig: NextConfig = { serverRuntimeConfig: {}, publicRuntimeConfig: {}, reactProductionProfiling: false, - reactStrictMode: false, + reactStrictMode: null, httpAgentOptions: { keepAlive: true, }, From 36fd16a398f4ed12a9f4df4803a90a1169bc9cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 31 Jul 2023 13:14:10 +0200 Subject: [PATCH 2/6] allow `null` for `reactStrictMode` --- packages/next/src/server/config-schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 49dbc1a53de19..d51ee7c759595 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -748,6 +748,7 @@ const configSchema = { }, reactStrictMode: { type: 'boolean', + nullable: true, }, redirects: { isFunction: true, From 95a07cdb59e79a25dfbebfcf83257e6695190ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Tue, 1 Aug 2023 14:52:55 +0200 Subject: [PATCH 3/6] add test --- .../app/layout.js | 7 ++++++ .../app/page.js | 9 ++++++++ .../next.config.js | 8 +++++++ .../strict-mode-enabled-by-default.test.ts | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 test/development/app-dir/strict-mode-enabled-by-default/app/layout.js create mode 100644 test/development/app-dir/strict-mode-enabled-by-default/app/page.js create mode 100644 test/development/app-dir/strict-mode-enabled-by-default/next.config.js create mode 100644 test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts diff --git a/test/development/app-dir/strict-mode-enabled-by-default/app/layout.js b/test/development/app-dir/strict-mode-enabled-by-default/app/layout.js new file mode 100644 index 0000000000000..a3a86a5ca1e12 --- /dev/null +++ b/test/development/app-dir/strict-mode-enabled-by-default/app/layout.js @@ -0,0 +1,7 @@ +export default function Root({ children }) { + return ( + + {children} + + ) +} diff --git a/test/development/app-dir/strict-mode-enabled-by-default/app/page.js b/test/development/app-dir/strict-mode-enabled-by-default/app/page.js new file mode 100644 index 0000000000000..e39b8a8c7a6d9 --- /dev/null +++ b/test/development/app-dir/strict-mode-enabled-by-default/app/page.js @@ -0,0 +1,9 @@ +'use client' +import { useEffect } from 'react' + +let i = 1 +export default function Page() { + useEffect(() => { + console.log(`logged ${i++} times`) + }, []) +} diff --git a/test/development/app-dir/strict-mode-enabled-by-default/next.config.js b/test/development/app-dir/strict-mode-enabled-by-default/next.config.js new file mode 100644 index 0000000000000..bb0cccf87020a --- /dev/null +++ b/test/development/app-dir/strict-mode-enabled-by-default/next.config.js @@ -0,0 +1,8 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + // REPLACEME +} + +module.exports = nextConfig diff --git a/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts b/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts new file mode 100644 index 0000000000000..cf8db58285eda --- /dev/null +++ b/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts @@ -0,0 +1,22 @@ +import { createNextDescribe } from 'e2e-utils' +import { BrowserInterface } from 'test/lib/browsers/base' + +createNextDescribe( + 'Strict Mode enabled by default', + { + files: __dirname, + }, + ({ next }) => { + // Recommended for tests that need a full browser + it('should work using browser', async () => { + const browser: BrowserInterface = await next.browser('/') + const logs = await browser.log() + expect(logs.length).toBe(2) + logs.forEach((log, i) => { + if (log.source === 'log') { + expect(log.message).toBe(`logged ${i + 1}`) + } + }) + }) + } +) From ff1b75aa9674ccc546187aa5a917ace1fb098168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Tue, 1 Aug 2023 14:54:31 +0200 Subject: [PATCH 4/6] remove empty config --- .../app-dir/strict-mode-enabled-by-default/next.config.js | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 test/development/app-dir/strict-mode-enabled-by-default/next.config.js diff --git a/test/development/app-dir/strict-mode-enabled-by-default/next.config.js b/test/development/app-dir/strict-mode-enabled-by-default/next.config.js deleted file mode 100644 index bb0cccf87020a..0000000000000 --- a/test/development/app-dir/strict-mode-enabled-by-default/next.config.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @type {import('next').NextConfig} - */ -const nextConfig = { - // REPLACEME -} - -module.exports = nextConfig From fd2d6f46debfbb247e72f28461165456a01bab8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 21 Aug 2023 15:08:01 +0200 Subject: [PATCH 5/6] fix test --- .../strict-mode-enabled-by-default.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts b/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts index cf8db58285eda..cf3c6240e3f06 100644 --- a/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts +++ b/test/development/app-dir/strict-mode-enabled-by-default/strict-mode-enabled-by-default.test.ts @@ -11,11 +11,12 @@ createNextDescribe( it('should work using browser', async () => { const browser: BrowserInterface = await next.browser('/') const logs = await browser.log() - expect(logs.length).toBe(2) - logs.forEach((log, i) => { - if (log.source === 'log') { - expect(log.message).toBe(`logged ${i + 1}`) - } + const userLogs = logs.filter( + (log) => log.source === 'log' && log.message.match(/logged \d times/) + ) + expect(userLogs.length).toBe(2) + userLogs.forEach((log, i) => { + expect(log.message).toBe(`logged ${i + 1} times`) }) }) } From 9b2dd4b0f403285c1eaef71dd618b5e022f0081d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Mon, 21 Aug 2023 15:40:30 +0200 Subject: [PATCH 6/6] make AppRouterAnnouncer resilient to Strict Mode --- packages/next/src/client/components/app-router-announcer.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/next/src/client/components/app-router-announcer.tsx b/packages/next/src/client/components/app-router-announcer.tsx index 7339498953aa3..b804e72d90add 100644 --- a/packages/next/src/client/components/app-router-announcer.tsx +++ b/packages/next/src/client/components/app-router-announcer.tsx @@ -57,7 +57,10 @@ export function AppRouterAnnouncer({ tree }: { tree: FlightRouterState }) { // Only announce the title change, but not for the first load because screen // readers do that automatically. - if (previousTitle.current !== undefined) { + if ( + previousTitle.current !== undefined && + previousTitle.current !== currentTitle + ) { setRouteAnnouncement(currentTitle) } previousTitle.current = currentTitle