diff --git a/.changeset/old-hornets-knock.md b/.changeset/old-hornets-knock.md
new file mode 100644
index 00000000..5346436e
--- /dev/null
+++ b/.changeset/old-hornets-knock.md
@@ -0,0 +1,5 @@
+---
+'@hono/react-renderer': major
+---
+
+feat: use React v19 and specify `react-dom/server.edge` for `renderToReadableStream`
diff --git a/package.json b/package.json
index 36924d1c..dae4347f 100644
--- a/package.json
+++ b/package.json
@@ -45,4 +45,4 @@
"vitest": "^3.0.8"
},
"packageManager": "yarn@4.0.2"
-}
\ No newline at end of file
+}
diff --git a/packages/node-ws/package.json b/packages/node-ws/package.json
index c925f215..9c03134b 100644
--- a/packages/node-ws/package.json
+++ b/packages/node-ws/package.json
@@ -57,4 +57,4 @@
"engines": {
"node": ">=18.14.1"
}
-}
\ No newline at end of file
+}
diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json
index df392532..45825e8d 100644
--- a/packages/react-renderer/package.json
+++ b/packages/react-renderer/package.json
@@ -40,17 +40,17 @@
"homepage": "https://github.com/honojs/middleware",
"peerDependencies": {
"hono": "*",
- "react": "*",
- "react-dom": "*"
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.4",
"@cloudflare/vitest-pool-workers": "^0.7.8",
- "@types/react": "^18",
- "@types/react-dom": "^18.2.17",
+ "@types/react": "^19.1.0",
+ "@types/react-dom": "^19.1.2",
"publint": "^0.3.9",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
"tsup": "^8.4.0",
"typescript": "^5.8.2",
"vitest": "^3.0.8"
diff --git a/packages/react-renderer/src/react-renderer.test.tsx b/packages/react-renderer/src/react-renderer.test.tsx
index bafa7768..88f6dd27 100644
--- a/packages/react-renderer/src/react-renderer.test.tsx
+++ b/packages/react-renderer/src/react-renderer.test.tsx
@@ -128,6 +128,7 @@ describe('Basic', () => {
({ children }) => {
return (
+
{children}
)
@@ -139,7 +140,9 @@ describe('Basic', () => {
const res = await app.request('/')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
- expect(await res.text()).toBe('Hello
')
+ expect(await res.text()).toBe(
+ 'Hello
'
+ )
})
it('Should return a content without a doctype', async () => {
@@ -161,7 +164,7 @@ describe('Basic', () => {
const res = await app.request('/')
expect(res).not.toBeNull()
expect(res.status).toBe(200)
- expect(await res.text()).toBe('Hello
')
+ expect(await res.text()).toBe('Hello
')
})
it('Should return a custom doctype', async () => {
@@ -187,7 +190,7 @@ describe('Basic', () => {
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe(
- 'Hello
'
+ 'Hello
'
)
})
@@ -231,6 +234,8 @@ describe('Streaming', () => {
expect(res.status).toBe(200)
expect(res.headers.get('Transfer-Encoding')).toBe('chunked')
expect(res.headers.get('Content-Type')).toBe('text/html; charset=UTF-8')
- expect(await res.text()).toBe('Hello
')
+ expect(await res.text()).toBe(
+ 'Hello
'
+ )
})
})
diff --git a/packages/react-renderer/src/react-renderer.ts b/packages/react-renderer/src/react-renderer.ts
index 0a9943b4..5b5b4135 100644
--- a/packages/react-renderer/src/react-renderer.ts
+++ b/packages/react-renderer/src/react-renderer.ts
@@ -30,10 +30,11 @@ const createRenderer =
options?: RendererOptions
) =>
async (children: React.ReactElement, props?: Props) => {
- const node = component ? component({ children, Layout, c, ...props }) : children
+ const node = component ? await component({ children, Layout, c, ...props }) : children
if (options?.stream) {
- const { renderToReadableStream } = await import('react-dom/server')
+ // @ts-expect-error `react-dom/server.edge` is not typed well
+ const { renderToReadableStream } = await import('react-dom/server.edge')
const stream = await renderToReadableStream(
React.createElement(RequestContext.Provider, { value: c }, node),
options.readableStreamOptions
@@ -52,8 +53,8 @@ const createRenderer =
typeof options?.docType === 'string'
? options.docType
: options?.docType === false
- ? ''
- : ''
+ ? ''
+ : ''
const body =
docType + renderToString(React.createElement(RequestContext.Provider, { value: c }, node))
return c.html(body)
@@ -71,7 +72,7 @@ export const reactRenderer = (
if (component) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
c.setLayout((props: any) => {
- return component({ ...props, Layout, c }, c)
+ return component({ ...props, Layout, c })
})
}
c.setRenderer(createRenderer(c, Layout, component, options))
diff --git a/yarn.lock b/yarn.lock
index 442686c4..1174ff11 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2197,18 +2197,18 @@ __metadata:
dependencies:
"@arethetypeswrong/cli": "npm:^0.17.4"
"@cloudflare/vitest-pool-workers": "npm:^0.7.8"
- "@types/react": "npm:^18"
- "@types/react-dom": "npm:^18.2.17"
+ "@types/react": "npm:^19.1.0"
+ "@types/react-dom": "npm:^19.1.2"
publint: "npm:^0.3.9"
- react: "npm:^18.2.0"
- react-dom: "npm:^18.2.0"
+ react: "npm:^19.1.0"
+ react-dom: "npm:^19.1.0"
tsup: "npm:^8.4.0"
typescript: "npm:^5.8.2"
vitest: "npm:^3.0.8"
peerDependencies:
hono: "*"
- react: "*"
- react-dom: "*"
+ react: ^19.0.0
+ react-dom: ^19.0.0
languageName: unknown
linkType: soft
@@ -3924,12 +3924,12 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-dom@npm:^18.2.17":
- version: 18.3.5
- resolution: "@types/react-dom@npm:18.3.5"
+"@types/react-dom@npm:^19.1.2":
+ version: 19.1.2
+ resolution: "@types/react-dom@npm:19.1.2"
peerDependencies:
- "@types/react": ^18.0.0
- checksum: b163d35a6b32a79f5782574a7aeb12a31a647e248792bf437e6d596e2676961c394c5e3c6e91d1ce44ae90441dbaf93158efb4f051c0d61e2612f1cb04ce4faa
+ "@types/react": ^19.0.0
+ checksum: 100c341cacba9ec8ae1d47ee051072a3450e9573bf8eeb7262490e341cb246ea0f95a07a1f2077e61cf92648f812a0324c602fcd811bd87b7ce41db2811510cd
languageName: node
linkType: hard
@@ -3943,6 +3943,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react@npm:^19.1.0":
+ version: 19.1.0
+ resolution: "@types/react@npm:19.1.0"
+ dependencies:
+ csstype: "npm:^3.0.2"
+ checksum: 632fd20ee176e55801a61c5f854141b043571a3e363ef106b047b766a813a12735cbb37abb3d61d126346979f530f2ed269a60c8ef3cdee54e5e9fe4174e5dad
+ languageName: node
+ linkType: hard
+
"@types/request@npm:^2.48.8":
version: 2.48.12
resolution: "@types/request@npm:2.48.12"
@@ -11882,15 +11891,14 @@ __metadata:
languageName: node
linkType: hard
-"react-dom@npm:^18.2.0":
- version: 18.3.1
- resolution: "react-dom@npm:18.3.1"
+"react-dom@npm:^19.1.0":
+ version: 19.1.0
+ resolution: "react-dom@npm:19.1.0"
dependencies:
- loose-envify: "npm:^1.1.0"
- scheduler: "npm:^0.23.2"
+ scheduler: "npm:^0.26.0"
peerDependencies:
- react: ^18.3.1
- checksum: a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85
+ react: ^19.1.0
+ checksum: 3e26e89bb6c67c9a6aa86cb888c7a7f8258f2e347a6d2a15299c17eb16e04c19194e3452bc3255bd34000a61e45e2cb51e46292392340432f133e5a5d2dfb5fc
languageName: node
linkType: hard
@@ -11903,6 +11911,13 @@ __metadata:
languageName: node
linkType: hard
+"react@npm:^19.1.0":
+ version: 19.1.0
+ resolution: "react@npm:19.1.0"
+ checksum: 530fb9a62237d54137a13d2cfb67a7db6a2156faed43eecc423f4713d9b20c6f2728b026b45e28fcd72e8eadb9e9ed4b089e99f5e295d2f0ad3134251bdd3698
+ languageName: node
+ linkType: hard
+
"read-yaml-file@npm:^1.1.0":
version: 1.1.0
resolution: "read-yaml-file@npm:1.1.0"
@@ -12610,12 +12625,10 @@ __metadata:
languageName: node
linkType: hard
-"scheduler@npm:^0.23.2":
- version: 0.23.2
- resolution: "scheduler@npm:0.23.2"
- dependencies:
- loose-envify: "npm:^1.1.0"
- checksum: 26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78
+"scheduler@npm:^0.26.0":
+ version: 0.26.0
+ resolution: "scheduler@npm:0.26.0"
+ checksum: 5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356
languageName: node
linkType: hard