Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt react 18 rc2 #35161

Merged
merged 4 commits into from Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -146,9 +146,9 @@
"pretty-ms": "7.0.0",
"random-seed": "0.3.0",
"react": "17.0.2",
"react-18": "npm:react@18.0.0-rc.1",
"react-18": "npm:react@18.0.0-rc.2",
"react-dom": "17.0.2",
"react-dom-18": "npm:react-dom@18.0.0-rc.1",
"react-dom-18": "npm:react-dom@18.0.0-rc.2",
"react-ssr-prepass": "1.0.8",
"react-virtualized": "9.22.3",
"relay-compiler": "13.0.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/next/server/config.ts
Expand Up @@ -733,7 +733,7 @@ export default async function loadConfig(
return completeConfig
}

export function shouldUseReactRoot() {
export const shouldUseReactRoot = execOnce(() => {
const reactDomVersion = require('react-dom').version
const isReactExperimental = Boolean(
reactDomVersion && /0\.0\.0-experimental/.test(reactDomVersion)
Expand All @@ -744,7 +744,7 @@ export function shouldUseReactRoot() {
semver.coerce(reactDomVersion)?.version === '18.0.0')

return hasReact18 || isReactExperimental
}
})

export function setHttpAgentOptions(
options: NextConfigComplete['httpAgentOptions']
Expand Down
29 changes: 5 additions & 24 deletions packages/next/server/render.tsx
Expand Up @@ -67,7 +67,6 @@ import isError from '../lib/is-error'
import { readableStreamTee } from './web/utils'
import { ImageConfigContext } from '../shared/lib/image-config-context'
import { FlushEffectsContext } from '../shared/lib/flush-effects'
import { execOnce } from '../shared/lib/utils'

let optimizeAmp: typeof import('./optimize-amp').default
let getFontDefinitionFromManifest: typeof import('./font-utils').getFontDefinitionFromManifest
Expand Down Expand Up @@ -1733,6 +1732,7 @@ function createFlushEffectStream(
return createTransformStream({
async transform(chunk, controller) {
const extraChunk = await handleFlushEffect()
// those should flush together at once
controller.enqueue(encodeText(extraChunk + decodeText(chunk)))
},
})
Expand All @@ -1755,31 +1755,12 @@ async function renderToStream({
}): Promise<ReadableStream<Uint8Array>> {
const closeTag = '</body></html>'
const suffixUnclosed = suffix ? suffix.split(closeTag)[0] : null

let completeCallback: (value?: unknown) => void
const allComplete = new Promise((resolveError, rejectError) => {
completeCallback = execOnce((err: unknown) => {
if (err) {
rejectError(err)
} else {
resolveError(null)
}
})
})

const renderStream: ReadableStream<Uint8Array> = await (
ReactDOMServer as any
).renderToReadableStream(element, {
onError(err: Error) {
completeCallback(err)
},
onCompleteAll() {
completeCallback()
},
})
const renderStream: ReadableStream<Uint8Array> & {
allReady?: Promise<void>
} = await (ReactDOMServer as any).renderToReadableStream(element)

if (generateStaticHTML) {
await allComplete
await renderStream.allReady
}

const transforms: Array<TransformStream<Uint8Array, Uint8Array>> = [
Expand Down
4 changes: 0 additions & 4 deletions test/integration/react-18/app/pages/index.js
Expand Up @@ -19,7 +19,3 @@ export default function Index() {
</div>
)
}

// export const config = {
// runtime: 'edge',
// }
@@ -1,5 +1,5 @@
let did = false
export default function Error() {
export default function MyError() {
if (!did && typeof window === 'undefined') {
did = true
throw new Error('oops')
Expand Down
@@ -1,7 +1,7 @@
import { Suspense } from 'react'

let did = false
function Error() {
function MyError() {
if (!did && typeof window === 'undefined') {
did = true
throw new Error('oops')
Expand All @@ -12,8 +12,8 @@ export default function page() {
return (
<>
<h1>Hey Error</h1>
<Suspense>
<Error />
<Suspense fallback="error-fallback">
<MyError />
</Suspense>
</>
)
Expand Down
Expand Up @@ -37,12 +37,21 @@ export default async function basic(context, { env }) {
})

it('should render 500 error correctly', async () => {
const html = await renderViaHTTP(context.appPort, '/err')
if (env === 'dev') {
// In dev mode it should show the error popup.
expect(html).toContain('Error: oops')
} else {
expect(html).toContain('custom-500-page')
}
const errPaths = ['/err', '/err/render']
const promises = errPaths.map(async (pagePath) => {
const html = await renderViaHTTP(context.appPort, pagePath)
if (env === 'dev') {
// In dev mode it should show the error popup.
expect(html).toContain('Error: oops')
} else {
expect(html).toContain('custom-500-page')
}
})
await Promise.all(promises)
})

it('should render fallback if error raised from suspense during streaming', async () => {
const html = await renderViaHTTP(context.appPort, '/err/suspense')
expect(html).toContain('error-fallback')
})
}
8 changes: 4 additions & 4 deletions test/production/react-18-streaming-ssr/index.test.ts
Expand Up @@ -24,8 +24,8 @@ describe('react 18 streaming SSR in minimal mode', () => {
},
},
dependencies: {
react: '18.0.0-rc.1',
'react-dom': '18.0.0-rc.1',
react: '18.0.0-rc.2',
'react-dom': '18.0.0-rc.2',
},
})
})
Expand Down Expand Up @@ -60,8 +60,8 @@ describe('react 18 streaming SSR with custom next configs', () => {
},
},
dependencies: {
react: '18.0.0-rc.1',
'react-dom': '18.0.0-rc.1',
react: '18.0.0-rc.2',
'react-dom': '18.0.0-rc.2',
},
})
})
Expand Down
20 changes: 10 additions & 10 deletions yarn.lock
Expand Up @@ -17778,20 +17778,20 @@ 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-rc.1":
version "18.0.0-rc.1"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-rc.1.tgz#fbaef1cbf8b1eddb36a869ee1ea723044aa670c2"
integrity sha512-IdvjOtyeFhITZwDrj+GMvY7kbWnGklRzNByO7/pOVIt0o3VZi++BUybpK3Fen1gDPkOZDP/rag7lSh6RZuWOeQ==
"react-18@npm:react@18.0.0-rc.2":
version "18.0.0-rc.2"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-rc.2.tgz#f54de68a912454331f7f718794fbf5e6c01eb855"
integrity sha512-q32FWyA5HvqfRCN0ZOk0gUOpzJGPPh8fqbk8DYQuh4DyiGWiNgN/BxMq3/ScY0SlwDB1HOAMU1lUgtaOr5p2Ng==
dependencies:
loose-envify "^1.1.0"

"react-dom-18@npm:react-dom@18.0.0-rc.1":
version "18.0.0-rc.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-rc.1.tgz#97296d5a5e7582e65ea0d82a9ccd5953aa05e7f6"
integrity sha512-BZ9NEwUp56MEguEwAzuh3u4bYE9Jv3QrzjaTmu11PV4C/lJCARTELEI16vjnHLq184GoJcCHMBrDILqlCrkZFQ==
"react-dom-18@npm:react-dom@18.0.0-rc.2":
version "18.0.0-rc.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-rc.2.tgz#b0a55afc2a2385e9e518071eaf7c89f0c214bba5"
integrity sha512-EvLlgtc/wAzAIXX5V1gnLgeK9B3wAdEGmmrXXKRoRzXM0RNNwGN+6OxQPBlACiGDUYYEOk+GT8f6u+gNWDnTtg==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.21.0-rc.1"
scheduler "^0.21.0-rc.2"

react-dom@17.0.2:
version "17.0.2"
Expand Down Expand Up @@ -18802,7 +18802,7 @@ scheduler@^0.20.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"

scheduler@^0.21.0-rc.1:
scheduler@^0.21.0-rc.2:
version "0.21.0-rc.1-next-f468816ef-20220225"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-rc.1-next-f468816ef-20220225.tgz#1909b9ce9e67de48f5ca06b52d98828401771e66"
integrity sha512-/maKldJ78Ba2o1e9kh2mUpqNZH7XrmSQ1o1aa3HUPN/OMotUB9+pBKX/y3Zihkjco21H4cujG9hK2sJOZUpzJw==
Expand Down