Skip to content

Commit 66bb034

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 2fab219 commit 66bb034

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
let ReactDOMServer
2+
3+
try {
4+
ReactDOMServer = require('react-dom/server.edge')
5+
} catch (error) {
6+
if (
7+
// TODO: copilot suggestion. Does this code actually exist?
8+
error.code !== 'MODULE_NOT_FOUND' &&
9+
// TODO: actually encountered that
10+
error.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED'
11+
) {
12+
throw error
13+
}
14+
// TODO: Ensure App Router does not bundle this
15+
// In React versions without react-dom/server.edge, the browser build works in Node.js.
16+
// The Node.js build does not support renderToReadableStream.
17+
ReactDOMServer = require('react-dom/server.browser')
18+
}
19+
20+
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
@@ -15,6 +15,8 @@ import {
1515
import loadConfig from 'next/dist/server/config'
1616
import path from 'path'
1717

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

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

0 commit comments

Comments
 (0)