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

Remove react root condition and always use concurrent mode #42141

Merged
merged 2 commits into from Oct 29, 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
7 changes: 0 additions & 7 deletions packages/next/bin/next.ts
Expand Up @@ -95,13 +95,6 @@ if (process.env.NODE_ENV) {
;(process.env as any).NODE_ENV = process.env.NODE_ENV || defaultEnv
;(process.env as any).NEXT_RUNTIME = 'nodejs'

// In node.js runtime, react has to be required after NODE_ENV is set,
// so that the correct dev/prod bundle could be loaded into require.cache.
const { shouldUseReactRoot } = require('../server/utils')
if (shouldUseReactRoot) {
;(process.env as any).__NEXT_REACT_ROOT = 'true'
}

// x-ref: https://github.com/vercel/next.js/pull/34688#issuecomment-1047994505
if (process.versions.pnp === '3') {
const nodeVersionParts = process.versions.node
Expand Down
3 changes: 0 additions & 3 deletions packages/next/build/index.ts
Expand Up @@ -274,8 +274,6 @@ export default async function build(
setGlobal('phase', PHASE_PRODUCTION_BUILD)
setGlobal('distDir', distDir)

const hasReactRoot = !!process.env.__NEXT_REACT_ROOT

const { target } = config
const buildId: string = await nextBuildSpan
.traceChild('generate-buildid')
Expand Down Expand Up @@ -910,7 +908,6 @@ export default async function build(
const commonWebpackOptions = {
buildId,
config,
hasReactRoot,
pagesDir,
reactProductionProfiling,
rewrites,
Expand Down
28 changes: 8 additions & 20 deletions packages/next/build/webpack-config.ts
@@ -1,3 +1,4 @@
import React from 'react'
import ReactRefreshWebpackPlugin from 'next/dist/compiled/@next/react-refresh-utils/dist/ReactRefreshWebpackPlugin'
import chalk from 'next/dist/compiled/chalk'
import crypto from 'crypto'
Expand Down Expand Up @@ -69,6 +70,10 @@ const NEXT_PROJECT_ROOT_DIST_CLIENT = path.join(
'client'
)

if (parseInt(React.version) < 18) {
throw new Error('Next.js requires react >= 18.2.0 to be installed.')
}

const babelIncludeRegexes: RegExp[] = [
/next[\\/]dist[\\/](esm[\\/])?shared[\\/]lib/,
/next[\\/]dist[\\/](esm[\\/])?client/,
Expand Down Expand Up @@ -161,7 +166,6 @@ export function getDefineEnv({
distDir,
isClient,
hasRewrites,
hasReactRoot,
isNodeServer,
isEdgeServer,
middlewareMatchers,
Expand All @@ -170,7 +174,6 @@ export function getDefineEnv({
distDir: string
isClient?: boolean
hasRewrites?: boolean
hasReactRoot?: boolean
isNodeServer?: boolean
isEdgeServer?: boolean
middlewareMatchers?: MiddlewareMatcher[]
Expand Down Expand Up @@ -255,7 +258,6 @@ export function getDefineEnv({
: false
: config.reactStrictMode
),
'process.env.__NEXT_REACT_ROOT': JSON.stringify(hasReactRoot),
'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify(
!dev && config.optimizeFonts
),
Expand Down Expand Up @@ -569,7 +571,6 @@ export default async function getBaseWebpackConfig(
compilerType,
dev = false,
entrypoints,
hasReactRoot,
isDevFallback = false,
pagesDir,
reactProductionProfiling = false,
Expand All @@ -584,7 +585,6 @@ export default async function getBaseWebpackConfig(
compilerType: CompilerNameValues
dev?: boolean
entrypoints: webpack.EntryObject
hasReactRoot: boolean
isDevFallback?: boolean
pagesDir?: string
reactProductionProfiling?: boolean
Expand All @@ -608,19 +608,8 @@ export default async function getBaseWebpackConfig(
rewrites.fallback.length > 0

const hasAppDir = !!config.experimental.appDir && !!appDir
const hasConcurrentFeatures = hasReactRoot
const hasServerComponents = hasAppDir

// Only error in first one compiler (client) once
if (isClient) {
if (!hasReactRoot) {
throw new Error('Next.js requires React 18.2.0 to be installed.')
}
}

const disableOptimizedLoading = hasConcurrentFeatures
? true
: config.experimental.disableOptimizedLoading
const disableOptimizedLoading = true

if (isClient) {
if (config.experimental.runtime === SERVER_RUNTIME.edge) {
Expand Down Expand Up @@ -1973,7 +1962,6 @@ export default async function getBaseWebpackConfig(
distDir,
isClient,
hasRewrites,
hasReactRoot,
isNodeServer,
isEdgeServer,
middlewareMatchers,
Expand All @@ -1983,7 +1971,7 @@ export default async function getBaseWebpackConfig(
new ReactLoadablePlugin({
filename: REACT_LOADABLE_MANIFEST,
pagesDir,
runtimeAsset: hasConcurrentFeatures
runtimeAsset: true
? `server/${MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js`
: undefined,
dev,
Expand Down Expand Up @@ -2056,7 +2044,7 @@ export default async function getBaseWebpackConfig(
buildId,
rewrites,
isDevFallback,
exportRuntime: hasConcurrentFeatures,
exportRuntime: true,
appDirEnabled: hasAppDir,
}),
new ProfilingPlugin({ runWebpackSpan }),
Expand Down
12 changes: 3 additions & 9 deletions packages/next/client/image.tsx
Expand Up @@ -794,19 +794,13 @@ export default function Image({
}
}

let imageSrcSetPropName = 'imagesrcset'
let imageSizesPropName = 'imagesizes'
if (process.env.__NEXT_REACT_ROOT) {
imageSrcSetPropName = 'imageSrcSet'
imageSizesPropName = 'imageSizes'
}
const linkProps: React.DetailedHTMLProps<
React.LinkHTMLAttributes<HTMLLinkElement>,
HTMLLinkElement
> = {
// Note: imagesrcset and imagesizes are not in the link element type with react 17.
[imageSrcSetPropName]: imgAttributes.srcSet,
[imageSizesPropName]: imgAttributes.sizes,
// @ts-expect-error upgrade react types to react 18
imageSrcSet: imgAttributes.srcSet,
imageSizes: imgAttributes.sizes,
crossOrigin: rest.crossOrigin,
}

Expand Down
36 changes: 12 additions & 24 deletions packages/next/client/index.tsx
@@ -1,10 +1,12 @@
/* global location */
import '../build/polyfills/polyfill-module'
import type Router from '../shared/lib/router/router'
import React from 'react'
// @ts-expect-error upgrade react types to react 18
import ReactDOM from 'react-dom/client'
import { HeadManagerContext } from '../shared/lib/head-manager-context'
import mitt, { MittEmitter } from '../shared/lib/mitt'
import { RouterContext } from '../shared/lib/router-context'
import type Router from '../shared/lib/router/router'
import {
AppComponent,
AppProps,
Expand Down Expand Up @@ -35,10 +37,6 @@ import { ImageConfigComplete } from '../shared/lib/image-config'
import { removeBasePath } from './remove-base-path'
import { hasBasePath } from './has-base-path'

const ReactDOM = process.env.__NEXT_REACT_ROOT
? require('react-dom/client')
: require('react-dom')

/// <reference types="react-dom/experimental" />

declare let __webpack_public_path__: string
Expand Down Expand Up @@ -492,26 +490,16 @@ function renderReactElement(
}

const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete)
if (process.env.__NEXT_REACT_ROOT) {
if (!reactRoot) {
// Unlike with createRoot, you don't need a separate root.render() call here
reactRoot = ReactDOM.hydrateRoot(domEl, reactEl)
// TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing
shouldHydrate = false
} else {
const startTransition = (React as any).startTransition
startTransition(() => {
reactRoot.render(reactEl)
})
}
if (!reactRoot) {
// Unlike with createRoot, you don't need a separate root.render() call here
reactRoot = ReactDOM.hydrateRoot(domEl, reactEl)
// TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing
shouldHydrate = false
} else {
// The check for `.hydrate` is there to support React alternatives like preact
if (shouldHydrate) {
ReactDOM.hydrate(reactEl, domEl)
shouldHydrate = false
} else {
ReactDOM.render(reactEl, domEl)
}
const startTransition = (React as any).startTransition
startTransition(() => {
reactRoot.render(reactEl)
})
}
}

Expand Down
12 changes: 3 additions & 9 deletions packages/next/client/legacy/image.tsx
Expand Up @@ -969,19 +969,13 @@ export default function Image({
}
}

let imageSrcSetPropName = 'imagesrcset'
let imageSizesPropName = 'imagesizes'
if (process.env.__NEXT_REACT_ROOT) {
imageSrcSetPropName = 'imageSrcSet'
imageSizesPropName = 'imageSizes'
}
const linkProps: React.DetailedHTMLProps<
React.LinkHTMLAttributes<HTMLLinkElement>,
HTMLLinkElement
> = {
// Note: imagesrcset and imagesizes are not in the link element type with react 17.
[imageSrcSetPropName]: imgAttributes.srcSet,
[imageSizesPropName]: imgAttributes.sizes,
// @ts-expect-error upgrade react types to react 18
imageSrcSet: imgAttributes.srcSet,
imageSizes: imgAttributes.sizes,
crossOrigin: rest.crossOrigin,
}

Expand Down
4 changes: 2 additions & 2 deletions packages/next/package.json
Expand Up @@ -84,8 +84,8 @@
"peerDependencies": {
"fibers": ">= 3.1.0",
"node-sass": "^6.0.0 || ^7.0.0",
"react": "^18.0.0-0",
"react-dom": "^18.0.0-0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
Expand Down
2 changes: 0 additions & 2 deletions packages/next/server/app-render.tsx
Expand Up @@ -23,7 +23,6 @@ import {
streamToString,
} from './node-web-streams-helper'
import { ESCAPE_REGEX, htmlEscapeJsonString } from './htmlescape'
import { shouldUseReactRoot } from './utils'
import { matchSegment } from '../client/components/match-segments'
import {
FlightCSSManifest,
Expand Down Expand Up @@ -671,7 +670,6 @@ function headersWithoutFlight(headers: IncomingHttpHeaders) {
}

async function renderToString(element: React.ReactElement) {
if (!shouldUseReactRoot) return ReactDOMServer.renderToString(element)
const renderStream = await ReactDOMServer.renderToReadableStream(element)
await renderStream.allReady
return streamToString(renderStream)
Expand Down
6 changes: 2 additions & 4 deletions packages/next/server/base-server.ts
Expand Up @@ -1150,10 +1150,8 @@ export default abstract class Server<ServerOptions extends Options = Options> {
const isBotRequest = isBot(req.headers['user-agent'] || '')
const isSupportedDocument =
typeof components.Document?.getInitialProps !== 'function' ||
// When concurrent features is enabled, the built-in `Document`
// component also supports dynamic HTML.
(!!process.env.__NEXT_REACT_ROOT &&
NEXT_BUILTIN_DOCUMENT in components.Document)
// The built-in `Document` component also supports dynamic HTML for concurrent mode.
NEXT_BUILTIN_DOCUMENT in components.Document

// Disable dynamic HTML in cases that we know it won't be generated,
// so that we can continue generating a cache key when possible.
Expand Down
6 changes: 1 addition & 5 deletions packages/next/server/dev/hot-reloader.ts
Expand Up @@ -163,7 +163,6 @@ export default class HotReloader {
private webpackHotMiddleware?: WebpackHotMiddleware
private config: NextConfigComplete
public hasServerComponents: boolean
public hasReactRoot: boolean
public clientStats: webpack.Stats | null
public serverStats: webpack.Stats | null
public edgeServerStats: webpack.Stats | null
Expand Down Expand Up @@ -216,8 +215,7 @@ export default class HotReloader {
this.serverPrevDocumentHash = null

this.config = config
this.hasReactRoot = !!process.env.__NEXT_REACT_ROOT
this.hasServerComponents = this.hasReactRoot && !!this.appDir
this.hasServerComponents = !!this.appDir
this.previewProps = previewProps
this.rewrites = rewrites
this.hotReloaderSpan = trace('hot-reloader', undefined, {
Expand Down Expand Up @@ -456,7 +454,6 @@ export default class HotReloader {
dev: true,
buildId: this.buildId,
config: this.config,
hasReactRoot: this.hasReactRoot,
pagesDir: this.pagesDir,
rewrites: this.rewrites,
runWebpackSpan: this.hotReloaderSpan,
Expand Down Expand Up @@ -521,7 +518,6 @@ export default class HotReloader {
pageExtensions: this.config.pageExtensions,
})
).client,
hasReactRoot: this.hasReactRoot,
})
const fallbackCompiler = webpack(fallbackConfig)

Expand Down
1 change: 0 additions & 1 deletion packages/next/server/dev/next-dev-server.ts
Expand Up @@ -547,7 +547,6 @@ export default class DevServer extends Server {
distDir: this.distDir,
isClient,
hasRewrites,
hasReactRoot: this.hotReloader?.hasReactRoot,
isNodeServer,
isEdgeServer,
})
Expand Down
5 changes: 0 additions & 5 deletions packages/next/server/next-server.ts
Expand Up @@ -94,15 +94,10 @@ import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
import { getClonableBody } from './body-streams'
import { checkIsManualRevalidate } from './api-utils'
import { shouldUseReactRoot } from './utils'
import ResponseCache from './response-cache'
import { IncrementalCache } from './lib/incremental-cache'
import { normalizeAppPath } from '../shared/lib/router/utils/app-paths'

if (shouldUseReactRoot) {
;(process.env as any).__NEXT_REACT_ROOT = 'true'
}

import { renderToHTMLOrFlight as appRenderToHTMLOrFlight } from './app-render'

export * from './base-server'
Expand Down
5 changes: 0 additions & 5 deletions packages/next/server/next.ts
Expand Up @@ -11,7 +11,6 @@ import { PHASE_DEVELOPMENT_SERVER } from '../shared/lib/constants'
import { PHASE_PRODUCTION_SERVER } from '../shared/lib/constants'
import { IncomingMessage, ServerResponse } from 'http'
import { NextUrlWithParsedQuery } from './request-meta'
import { shouldUseReactRoot } from './utils'
import {
loadRequireHook,
overrideBuiltInReactPackages,
Expand Down Expand Up @@ -211,10 +210,6 @@ function createServer(options: NextServerOptions): NextServer {
)
}

if (shouldUseReactRoot) {
;(process.env as any).__NEXT_REACT_ROOT = 'true'
}

return new NextServer(options)
}

Expand Down