Skip to content

Commit 82f2a06

Browse files
committed
Fall back to react-dom/server.browser in Pages router when React 18 is installed
React 18 has no `react-dom/server.edge`
1 parent 141b90a commit 82f2a06

File tree

4 files changed

+44
-5
lines changed

4 files changed

+44
-5
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from 'react-dom/server.edge'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
let ReactDOMServer
2+
3+
try {
4+
ReactDOMServer = require('react-dom/server.edge')
5+
} catch (error) {
6+
if (
7+
error.code !== 'MODULE_NOT_FOUND' &&
8+
error.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED'
9+
) {
10+
throw error
11+
}
12+
// In React versions without react-dom/server.edge, the browser build works in Node.js.
13+
// The Node.js build does not support renderToReadableStream.
14+
ReactDOMServer = require('react-dom/server.browser')
15+
}
16+
17+
module.exports = ReactDOMServer

packages/next/src/server/render.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import type { Revalidate, SwrDelta } from './lib/revalidate'
4040
import type { COMPILER_NAMES } from '../shared/lib/constants'
4141

4242
import React, { type JSX } from 'react'
43-
import ReactDOMServerBrowser from 'react-dom/server.browser'
43+
import ReactDOMServerPages from './ReactDOMServerPages'
4444
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
4545
import {
4646
GSP_NO_RETURNED_VALUE,
@@ -127,8 +127,7 @@ function noRouter() {
127127
}
128128

129129
async function renderToString(element: React.ReactElement) {
130-
const renderStream =
131-
await ReactDOMServerBrowser.renderToReadableStream(element)
130+
const renderStream = await ReactDOMServerPages.renderToReadableStream(element)
132131
await renderStream.allReady
133132
return streamToString(renderStream)
134133
}
@@ -1327,7 +1326,7 @@ export async function renderToHTMLImpl(
13271326
) => {
13281327
const content = renderContent(EnhancedApp, EnhancedComponent)
13291328
return await renderToInitialFizzStream({
1330-
ReactDOMServer: ReactDOMServerBrowser,
1329+
ReactDOMServer: ReactDOMServerPages,
13311330
element: content,
13321331
})
13331332
}

test/development/basic/next-rs-api.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import type {
1414
import loadConfig from 'next/dist/server/config'
1515
import path from 'path'
1616

17+
const isReact18 = parseInt(process.env.NEXT_TEST_REACT_VERSION) === 18
18+
1719
function normalizePath(path: string) {
1820
return path
1921
.replace(/\[project\].+\/node_modules\//g, '[project]/.../node_modules/')
@@ -40,6 +42,21 @@ function styledStringToMarkdown(styled: StyledString): string {
4042
}
4143
}
4244

45+
function isReactDOMServerEdgeConditionalBundlingIssue(issue: {
46+
description?: Issue['description']
47+
filePath: string
48+
}) {
49+
return (
50+
isReact18 &&
51+
issue.filePath ===
52+
'[project]/.../node_modules/next/dist/esm/server/ReactDOMServerPages.js' &&
53+
issue.description?.type === 'text' &&
54+
issue.description?.value.includes(
55+
'Import map: aliased to module "react-dom" with subpath "/server.edge" inside of [project]/'
56+
)
57+
)
58+
}
59+
4360
function normalizeIssues(issues: Issue[]) {
4461
return issues
4562
.map((issue) => ({
@@ -52,6 +69,11 @@ function normalizeIssues(issues: Issue[]) {
5269
source: normalizePath(issue.source.source.ident),
5370
},
5471
}))
72+
.filter((issue) => {
73+
// The conditional bundling is wrapped in a try-catch.
74+
// It doesn't surface to the user, so it's safe to ignore here.
75+
return !isReactDOMServerEdgeConditionalBundlingIssue(issue)
76+
})
5577
.sort((a, b) => {
5678
const a_ = JSON.stringify(a)
5779
const b_ = JSON.stringify(b)
@@ -503,7 +525,7 @@ describe('next.rs api', () => {
503525
expect(result.done).toBe(false)
504526
expect(result.value).toHaveProperty('resource', expect.toBeObject())
505527
expect(result.value).toHaveProperty('type', 'issues')
506-
expect(result.value).toHaveProperty('issues', expect.toBeEmpty())
528+
expect(normalizeIssues(result.value.issues)).toEqual([])
507529
expect(result.value).toHaveProperty(
508530
'diagnostics',
509531
expect.toBeEmpty()

0 commit comments

Comments
 (0)