From 9704163bf1795ab29651c1d8bbcc13d8b25d8b6b Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 28 Jun 2021 00:12:37 +0800 Subject: [PATCH 1/6] fix: react 18 new hydration API --- package.json | 2 + packages/next/client/index.tsx | 16 +++++--- .../node_modules/react-dom/index.js | 39 ++++++++++++++++++- .../node_modules/react-dom/package.json | 2 +- .../react-18/supported/next.config.js | 5 +++ .../react-18/supported/pages/index.js | 4 ++ test/integration/react-18/test/index.test.js | 37 +++++++++++++++++- yarn.lock | 25 ++++++++++++ 8 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 test/integration/react-18/supported/next.config.js diff --git a/package.json b/package.json index c31b45d07d002..113bd996c4056 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,9 @@ "pretty-bytes": "5.3.0", "pretty-ms": "7.0.0", "react": "17.0.2", + "react-18": "npm:react@18", "react-dom": "17.0.2", + "react-dom-18": "npm:react-dom@18", "react-ssr-prepass": "1.0.8", "release": "6.3.0", "request-promise-core": "1.1.2", diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 32b6558c42b88..dbc75cf172711 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -493,8 +493,10 @@ export function renderError(renderErrorProps: RenderErrorProps): Promise { }) } +const ReactDOM18: any = ReactDOM as any let reactRoot: any = null -let shouldHydrate: boolean = typeof ReactDOM.hydrate === 'function' +let shouldHydrate: boolean = + typeof (ReactDOM.hydrate || ReactDOM18.hydrateRoot) === 'function' function renderReactElement( domEl: HTMLElement, @@ -508,12 +510,14 @@ function renderReactElement( const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete) if (process.env.__NEXT_REACT_ROOT) { if (!reactRoot) { - reactRoot = (ReactDOM as any).createRoot(domEl, { - hydrate: shouldHydrate, - }) + if (shouldHydrate && typeof ReactDOM18.hydrateRoot === 'function') { + reactRoot = ReactDOM18.hydrateRoot(domEl, reactEl) + } else { + reactRoot = ReactDOM18.createRoot(domEl, { hydrate: shouldHydrate }) + reactRoot.render(reactEl) + } + shouldHydrate = false } - reactRoot.render(reactEl) - shouldHydrate = false } else { // The check for `.hydrate` is there to support React alternatives like preact if (shouldHydrate) { diff --git a/test/integration/react-18/prerelease/node_modules/react-dom/index.js b/test/integration/react-18/prerelease/node_modules/react-dom/index.js index 27d7f6e85eb30..1c36a9b284a58 100644 --- a/test/integration/react-18/prerelease/node_modules/react-dom/index.js +++ b/test/integration/react-18/prerelease/node_modules/react-dom/index.js @@ -1 +1,38 @@ -module.exports = { Suspense: true } +'use strict' + +function checkDCE() { + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ + if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function' + ) { + return + } + if (process.env.NODE_ENV !== 'production') { + // This branch is unreachable because this function is only called + // in production, but the condition is true only in development. + // Therefore if the branch is still here, dead code elimination wasn't + // properly applied. + // Don't change the message. React DevTools relies on it. Also make sure + // this message doesn't occur elsewhere in this function, or it will cause + // a false positive. + throw new Error('^_^') + } + try { + // Verify that the code above has been dead code eliminated (DCE'd). + __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE) + } catch (err) { + // DevTools shouldn't crash React, no matter what. + // We should still report in case we break this code. + console.error(err) + } +} + +if (process.env.NODE_ENV === 'production') { + // DCE check should happen before ReactDOM bundle executes so that + // DevTools can report bad minification during injection. + checkDCE() + module.exports = require('./cjs/react-dom.production.min.js') +} else { + module.exports = require('./cjs/react-dom.development.js') +} diff --git a/test/integration/react-18/prerelease/node_modules/react-dom/package.json b/test/integration/react-18/prerelease/node_modules/react-dom/package.json index f89a61e597a6e..42324da484c86 100644 --- a/test/integration/react-18/prerelease/node_modules/react-dom/package.json +++ b/test/integration/react-18/prerelease/node_modules/react-dom/package.json @@ -1,4 +1,4 @@ { "name": "react-dom", - "version": "18.0.0-alpha-43f4cc160" + "version": "18.0.0-alpha-e6be2d531" } diff --git a/test/integration/react-18/supported/next.config.js b/test/integration/react-18/supported/next.config.js new file mode 100644 index 0000000000000..c981dcdb8c8b6 --- /dev/null +++ b/test/integration/react-18/supported/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + reactRoot: true, + }, +} diff --git a/test/integration/react-18/supported/pages/index.js b/test/integration/react-18/supported/pages/index.js index fb077e8078c9e..a34e4ef37de18 100644 --- a/test/integration/react-18/supported/pages/index.js +++ b/test/integration/react-18/supported/pages/index.js @@ -1,3 +1,7 @@ export default function Index() { + if (typeof window !== 'undefined') { + window.didHydrate = true + } + return 'details' return

Hello

} diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index 8395643309eb1..49b92f5672df8 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -1,7 +1,16 @@ /* eslint-env jest */ -import { findPort, killApp, launchApp, runNextCommand } from 'next-test-utils' import { join } from 'path' +import fs from 'fs-extra' +import webdriver from 'next-webdriver' +import { + findPort, + killApp, + launchApp, + runNextCommand, + nextBuild, + nextStart, +} from 'next-test-utils' jest.setTimeout(1000 * 60 * 5) @@ -67,4 +76,30 @@ describe('React 18 Support', () => { expect(output).toMatch(UNSUPPORTED_PRERELEASE) }) }) + + describe('hydration', () => { + const appDir = join(__dirname, '../prerelease') + let app + let appPort + beforeAll(async () => { + jest.mock('react', () => { + return jest.requireActual('react-18') + }) + jest.mock('react-dom', () => { + return jest.requireActual('react-dom-18') + }) + await fs.remove(join(appDir, '.next')) + const { stderr } = await nextBuild(appDir, [dirPrerelease], { + stderr: true, + }) + console.error(stderr) + appPort = await findPort() + app = await nextStart(appDir, appPort, { stderr: true }) + }) + afterAll(async () => await killApp(app)) + it('hydrates correctly for normal page', async () => { + const browser = await webdriver(appPort, '/') + expect(await browser.eval('window.didHydrate')).toBe(true) + }) + }) }) diff --git a/yarn.lock b/yarn.lock index f5cae140c25d8..e20f8464a50e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15632,6 +15632,23 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +"react-18@npm:react@18": + version "18.0.0-alpha-e6be2d531" + resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-e6be2d531.tgz#c5cf6d5706f7b6411d36848b483a7937c94fc5c9" + integrity sha512-roZmm4MYfuGN65PiagPvhumBb3Da1FAgyj6Ti2sHwQDIxhi40PMq5V90gBSKXl7qXbaXHrtpuAtG5R+XkqpDYA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +"react-dom-18@npm:react-dom@18": + version "18.0.0-alpha-e6be2d531" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-e6be2d531.tgz#89b1aef488a56ceac7cc0169ae02d7fbb58cbbb6" + integrity sha512-mMGiX/kyhxaUTRDt+Q5oIbpU6cPvO8Sp/kHz3cdNFviwVTHHF2YrnnD70BD2F1R0b7wAdfVVit9EfE+Rqt0sJA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "0.21.0-alpha-e6be2d531" + react-dom@17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -16649,6 +16666,14 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" +scheduler@0.21.0-alpha-e6be2d531: + version "0.21.0-alpha-e6be2d531" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-alpha-e6be2d531.tgz#fd895f7426e15166f1b16ed1d54de48243c78002" + integrity sha512-1GSnBp3em+oMz93ncjqR/7qeGArhgKaOWluZUrQW2JgHEGYISXAhGTVQhUYAiKc3F9jiq94CE1WrO0vaVzgReQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" From 85db7d6ea8ece9e8ed2715f913222a564b34c377 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 28 Jun 2021 00:59:54 +0800 Subject: [PATCH 2/6] support react 18 --- package.json | 4 +- packages/next/client/index.tsx | 2 +- .../react-18/prerelease/next.config.js | 14 +++++++ .../node_modules/react-dom/index.js | 38 ------------------- .../react-18/prerelease/package.json | 1 + .../react-18/prerelease/pages/index.js | 3 ++ .../react-18/supported/next.config.js | 5 --- .../react-18/supported/pages/index.js | 4 -- test/integration/react-18/test/index.test.js | 13 +------ yarn.lock | 4 +- 10 files changed, 25 insertions(+), 63 deletions(-) create mode 100644 test/integration/react-18/prerelease/next.config.js delete mode 100644 test/integration/react-18/prerelease/node_modules/react-dom/index.js delete mode 100644 test/integration/react-18/supported/next.config.js diff --git a/package.json b/package.json index 113bd996c4056..1293175eb1288 100644 --- a/package.json +++ b/package.json @@ -115,9 +115,9 @@ "pretty-bytes": "5.3.0", "pretty-ms": "7.0.0", "react": "17.0.2", - "react-18": "npm:react@18", + "react-18": "npm:react@18.0.0-alpha-e6be2d531", "react-dom": "17.0.2", - "react-dom-18": "npm:react-dom@18", + "react-dom-18": "npm:react-dom@18.0.0-alpha-e6be2d531", "react-ssr-prepass": "1.0.8", "release": "6.3.0", "request-promise-core": "1.1.2", diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index dbc75cf172711..d6c595e933ea6 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -516,8 +516,8 @@ function renderReactElement( reactRoot = ReactDOM18.createRoot(domEl, { hydrate: shouldHydrate }) reactRoot.render(reactEl) } - shouldHydrate = false } + shouldHydrate = false } else { // The check for `.hydrate` is there to support React alternatives like preact if (shouldHydrate) { diff --git a/test/integration/react-18/prerelease/next.config.js b/test/integration/react-18/prerelease/next.config.js new file mode 100644 index 0000000000000..21f2ba0abbec5 --- /dev/null +++ b/test/integration/react-18/prerelease/next.config.js @@ -0,0 +1,14 @@ +module.exports = { + webpack(config) { + const { alias } = config.resolve + // FIXME: resolving react/jsx-runtime https://github.com/facebook/react/issues/20235 + alias['react/jsx-dev-runtime'] = require.resolve('react/jsx-dev-runtime.js') + alias['react/jsx-runtime'] = require.resolve('react/jsx-runtime.js') + + // Use react 18 + alias['react'] = require.resolve('react-18') + alias['react-dom'] = require.resolve('react-dom-18') + + return config + }, +} diff --git a/test/integration/react-18/prerelease/node_modules/react-dom/index.js b/test/integration/react-18/prerelease/node_modules/react-dom/index.js deleted file mode 100644 index 1c36a9b284a58..0000000000000 --- a/test/integration/react-18/prerelease/node_modules/react-dom/index.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict' - -function checkDCE() { - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function' - ) { - return - } - if (process.env.NODE_ENV !== 'production') { - // This branch is unreachable because this function is only called - // in production, but the condition is true only in development. - // Therefore if the branch is still here, dead code elimination wasn't - // properly applied. - // Don't change the message. React DevTools relies on it. Also make sure - // this message doesn't occur elsewhere in this function, or it will cause - // a false positive. - throw new Error('^_^') - } - try { - // Verify that the code above has been dead code eliminated (DCE'd). - __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE) - } catch (err) { - // DevTools shouldn't crash React, no matter what. - // We should still report in case we break this code. - console.error(err) - } -} - -if (process.env.NODE_ENV === 'production') { - // DCE check should happen before ReactDOM bundle executes so that - // DevTools can report bad minification during injection. - checkDCE() - module.exports = require('./cjs/react-dom.production.min.js') -} else { - module.exports = require('./cjs/react-dom.development.js') -} diff --git a/test/integration/react-18/prerelease/package.json b/test/integration/react-18/prerelease/package.json index 1e0b54f840c56..be823a58af7d7 100644 --- a/test/integration/react-18/prerelease/package.json +++ b/test/integration/react-18/prerelease/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "react": "*", "react-dom": "*" } } diff --git a/test/integration/react-18/prerelease/pages/index.js b/test/integration/react-18/prerelease/pages/index.js index fb077e8078c9e..17c78ff7937ea 100644 --- a/test/integration/react-18/prerelease/pages/index.js +++ b/test/integration/react-18/prerelease/pages/index.js @@ -1,3 +1,6 @@ export default function Index() { + if (typeof window !== 'undefined') { + window.didHydrate = true + } return

Hello

} diff --git a/test/integration/react-18/supported/next.config.js b/test/integration/react-18/supported/next.config.js deleted file mode 100644 index c981dcdb8c8b6..0000000000000 --- a/test/integration/react-18/supported/next.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - experimental: { - reactRoot: true, - }, -} diff --git a/test/integration/react-18/supported/pages/index.js b/test/integration/react-18/supported/pages/index.js index a34e4ef37de18..fb077e8078c9e 100644 --- a/test/integration/react-18/supported/pages/index.js +++ b/test/integration/react-18/supported/pages/index.js @@ -1,7 +1,3 @@ export default function Index() { - if (typeof window !== 'undefined') { - window.didHydrate = true - } - return 'details' return

Hello

} diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index 49b92f5672df8..cd866a82e528f 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -82,19 +82,10 @@ describe('React 18 Support', () => { let app let appPort beforeAll(async () => { - jest.mock('react', () => { - return jest.requireActual('react-18') - }) - jest.mock('react-dom', () => { - return jest.requireActual('react-dom-18') - }) await fs.remove(join(appDir, '.next')) - const { stderr } = await nextBuild(appDir, [dirPrerelease], { - stderr: true, - }) - console.error(stderr) + await nextBuild(appDir, [dirPrerelease]) appPort = await findPort() - app = await nextStart(appDir, appPort, { stderr: true }) + app = await nextStart(appDir, appPort) }) afterAll(async () => await killApp(app)) it('hydrates correctly for normal page', async () => { diff --git a/yarn.lock b/yarn.lock index e20f8464a50e2..7e56531b9506d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15632,7 +15632,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -"react-18@npm:react@18": +"react-18@npm:react@18.0.0-alpha-e6be2d531": version "18.0.0-alpha-e6be2d531" resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-e6be2d531.tgz#c5cf6d5706f7b6411d36848b483a7937c94fc5c9" integrity sha512-roZmm4MYfuGN65PiagPvhumBb3Da1FAgyj6Ti2sHwQDIxhi40PMq5V90gBSKXl7qXbaXHrtpuAtG5R+XkqpDYA== @@ -15640,7 +15640,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: loose-envify "^1.1.0" object-assign "^4.1.1" -"react-dom-18@npm:react-dom@18": +"react-dom-18@npm:react-dom@18.0.0-alpha-e6be2d531": version "18.0.0-alpha-e6be2d531" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-e6be2d531.tgz#89b1aef488a56ceac7cc0169ae02d7fbb58cbbb6" integrity sha512-mMGiX/kyhxaUTRDt+Q5oIbpU6cPvO8Sp/kHz3cdNFviwVTHHF2YrnnD70BD2F1R0b7wAdfVVit9EfE+Rqt0sJA== From bcffc8376f97a8a6eef9c8617da0aac09d9362e5 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 28 Jun 2021 16:56:45 +0800 Subject: [PATCH 3/6] compat latest react only, fix resolved version --- package.json | 4 ++-- packages/next/client/index.tsx | 4 ++-- yarn.lock | 26 +++++++++++++------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 1293175eb1288..f0fa1bf9c2e7e 100644 --- a/package.json +++ b/package.json @@ -115,9 +115,9 @@ "pretty-bytes": "5.3.0", "pretty-ms": "7.0.0", "react": "17.0.2", - "react-18": "npm:react@18.0.0-alpha-e6be2d531", + "react-18": "npm:react@next", "react-dom": "17.0.2", - "react-dom-18": "npm:react-dom@18.0.0-alpha-e6be2d531", + "react-dom-18": "npm:react-dom@next", "react-ssr-prepass": "1.0.8", "release": "6.3.0", "request-promise-core": "1.1.2", diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index d6c595e933ea6..4e10c3d56498e 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -510,10 +510,10 @@ function renderReactElement( const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete) if (process.env.__NEXT_REACT_ROOT) { if (!reactRoot) { - if (shouldHydrate && typeof ReactDOM18.hydrateRoot === 'function') { + if (shouldHydrate) { reactRoot = ReactDOM18.hydrateRoot(domEl, reactEl) } else { - reactRoot = ReactDOM18.createRoot(domEl, { hydrate: shouldHydrate }) + reactRoot = ReactDOM18.createRoot(domEl) reactRoot.render(reactEl) } } diff --git a/yarn.lock b/yarn.lock index 7e56531b9506d..227fdef6dae14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15632,22 +15632,22 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -"react-18@npm:react@18.0.0-alpha-e6be2d531": - version "18.0.0-alpha-e6be2d531" - resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-e6be2d531.tgz#c5cf6d5706f7b6411d36848b483a7937c94fc5c9" - integrity sha512-roZmm4MYfuGN65PiagPvhumBb3Da1FAgyj6Ti2sHwQDIxhi40PMq5V90gBSKXl7qXbaXHrtpuAtG5R+XkqpDYA== +"react-18@npm:react@next": + version "18.0.0-alpha-73ffce1b6-20210624" + resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-73ffce1b6-20210624.tgz#d9fb8700c6fad8de752ec0427f2ae3a941eea951" + integrity sha512-Qaj2vhrMlYc169Yh0gXBB7WeKWMeIVx99JnuouuT71Jku2Cly9TxAWurc+h6PSgz/qjjmDA2NOtHCb6mGlmzGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" -"react-dom-18@npm:react-dom@18.0.0-alpha-e6be2d531": - version "18.0.0-alpha-e6be2d531" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-e6be2d531.tgz#89b1aef488a56ceac7cc0169ae02d7fbb58cbbb6" - integrity sha512-mMGiX/kyhxaUTRDt+Q5oIbpU6cPvO8Sp/kHz3cdNFviwVTHHF2YrnnD70BD2F1R0b7wAdfVVit9EfE+Rqt0sJA== +"react-dom-18@npm:react-dom@next": + version "18.0.0-alpha-73ffce1b6-20210624" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-73ffce1b6-20210624.tgz#3d789e4f3446abc685a7754c8dc74dea0ffb4247" + integrity sha512-TgA+VhVas3mJdhy6AQLXnPzBN2JeNKC7EGhLKU11XOxUODCGQ94nyT04i1ta2R3Fv0QevMLp0Wb5hccan0wMEg== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - scheduler "0.21.0-alpha-e6be2d531" + scheduler "0.21.0-alpha-73ffce1b6-20210624" react-dom@17.0.2: version "17.0.2" @@ -16666,10 +16666,10 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -scheduler@0.21.0-alpha-e6be2d531: - version "0.21.0-alpha-e6be2d531" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-alpha-e6be2d531.tgz#fd895f7426e15166f1b16ed1d54de48243c78002" - integrity sha512-1GSnBp3em+oMz93ncjqR/7qeGArhgKaOWluZUrQW2JgHEGYISXAhGTVQhUYAiKc3F9jiq94CE1WrO0vaVzgReQ== +scheduler@0.21.0-alpha-73ffce1b6-20210624: + version "0.21.0-alpha-73ffce1b6-20210624" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-alpha-73ffce1b6-20210624.tgz#6fff95e26af73cfaa365b68fa3b68c4c66dfe347" + integrity sha512-7SXTiepGRo63F5Yp/fxLhZDYi5TInsqjnMTYF6GwtunUGAwyuK4V/AFiF0Q1gtB32U/e+C+OE4SSj9LtBYBjYw== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" From c920437a8b987d3dca263dd555811e3f011e3ff6 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 28 Jun 2021 18:12:50 +0800 Subject: [PATCH 4/6] fix tests --- test/integration/build-output/test/index.test.js | 4 ++-- test/integration/fallback-modules/test/index.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/build-output/test/index.test.js b/test/integration/build-output/test/index.test.js index ef085280f3d45..8446d499926ba 100644 --- a/test/integration/build-output/test/index.test.js +++ b/test/integration/build-output/test/index.test.js @@ -132,7 +132,7 @@ describe('Build Output', () => { expect(parseFloat(err404FirstLoad)).toBeCloseTo(gz ? 66.9 : 205, 1) expect(err404FirstLoad.endsWith('kB')).toBe(true) - expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63.7 : 196, 1) + expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63.8 : 196, 1) expect(sharedByAll.endsWith('kB')).toBe(true) const appSizeValue = _appSize.endsWith('kB') @@ -149,7 +149,7 @@ describe('Build Output', () => { true ) - expect(parseFloat(mainSize)).toBeCloseTo(gz ? 20.1 : 62.7, 1) + expect(parseFloat(mainSize)).toBeCloseTo(gz ? 20.2 : 62.8, 1) expect(mainSize.endsWith('kB')).toBe(true) expect(parseFloat(frameworkSize)).toBeCloseTo(gz ? 42.0 : 130, 1) diff --git a/test/integration/fallback-modules/test/index.test.js b/test/integration/fallback-modules/test/index.test.js index 57558d4eef5e3..eda446c171553 100644 --- a/test/integration/fallback-modules/test/index.test.js +++ b/test/integration/fallback-modules/test/index.test.js @@ -49,7 +49,7 @@ describe('Build Output', () => { expect(indexSize.endsWith('kB')).toBe(true) expect(parseFloat(indexFirstLoad)).toBeLessThanOrEqual( - process.env.NEXT_PRIVATE_TEST_WEBPACK4_MODE ? 68 : 67.9 + process.env.NEXT_PRIVATE_TEST_WEBPACK4_MODE ? 68.1 : 67.9 ) expect(parseFloat(indexFirstLoad)).toBeGreaterThanOrEqual(60) expect(indexFirstLoad.endsWith('kB')).toBe(true) From 8d741a7f19e3e3742e3a4c960e9906a6c165b60a Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 30 Jun 2021 10:48:35 +0200 Subject: [PATCH 5/6] Some changes based on https://github.com/reactwg/react-18/discussions/5 --- packages/next/client/index.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 4e10c3d56498e..92755ae277c4d 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -493,10 +493,9 @@ export function renderError(renderErrorProps: RenderErrorProps): Promise { }) } -const ReactDOM18: any = ReactDOM as any let reactRoot: any = null -let shouldHydrate: boolean = - typeof (ReactDOM.hydrate || ReactDOM18.hydrateRoot) === 'function' +// On initial render a hydrate should always happen +let shouldHydrate: boolean = true function renderReactElement( domEl: HTMLElement, @@ -510,14 +509,13 @@ function renderReactElement( const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete) if (process.env.__NEXT_REACT_ROOT) { if (!reactRoot) { - if (shouldHydrate) { - reactRoot = ReactDOM18.hydrateRoot(domEl, reactEl) - } else { - reactRoot = ReactDOM18.createRoot(domEl) - reactRoot.render(reactEl) - } + // Unlike with createRoot, you don't need a separate root.render() call here + reactRoot = (ReactDOM as any).hydrateRoot(domEl, reactEl) + // TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing + shouldHydrate = false + } else { + reactRoot.render(reactEl) } - shouldHydrate = false } else { // The check for `.hydrate` is there to support React alternatives like preact if (shouldHydrate) { From 213d155e29c7df9fc8585f977c4f77146fc3b57b Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 30 Jun 2021 17:32:43 +0800 Subject: [PATCH 6/6] fix test --- test/integration/build-output/test/index.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/build-output/test/index.test.js b/test/integration/build-output/test/index.test.js index 8446d499926ba..c8a679732174f 100644 --- a/test/integration/build-output/test/index.test.js +++ b/test/integration/build-output/test/index.test.js @@ -129,10 +129,10 @@ describe('Build Output', () => { expect(parseFloat(err404Size)).toBeCloseTo(gz ? 3.17 : 8.51, 1) expect(err404Size.endsWith('kB')).toBe(true) - expect(parseFloat(err404FirstLoad)).toBeCloseTo(gz ? 66.9 : 205, 1) + expect(parseFloat(err404FirstLoad)).toBeCloseTo(gz ? 66.9 : 204, 1) expect(err404FirstLoad.endsWith('kB')).toBe(true) - expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63.8 : 196, 1) + expect(parseFloat(sharedByAll)).toBeCloseTo(gz ? 63.7 : 196, 1) expect(sharedByAll.endsWith('kB')).toBe(true) const appSizeValue = _appSize.endsWith('kB')