feat(react-renderer): use React v19 and specify `react-dom/server.edge` for `renderToReadableStream` (#1119)
* feat(react-renderer): use React v19 and specify `react-dom/server.edge` for `renderToReadableStream` * changesetpull/1121/head
parent
ca3cada076
commit
684ae9a21d
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@hono/react-renderer': major
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: use React v19 and specify `react-dom/server.edge` for `renderToReadableStream`
|
|
@ -40,17 +40,17 @@
|
||||||
"homepage": "https://github.com/honojs/middleware",
|
"homepage": "https://github.com/honojs/middleware",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hono": "*",
|
"hono": "*",
|
||||||
"react": "*",
|
"react": "^19.0.0",
|
||||||
"react-dom": "*"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@arethetypeswrong/cli": "^0.17.4",
|
"@arethetypeswrong/cli": "^0.17.4",
|
||||||
"@cloudflare/vitest-pool-workers": "^0.7.8",
|
"@cloudflare/vitest-pool-workers": "^0.7.8",
|
||||||
"@types/react": "^18",
|
"@types/react": "^19.1.0",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^19.1.2",
|
||||||
"publint": "^0.3.9",
|
"publint": "^0.3.9",
|
||||||
"react": "^18.2.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^19.1.0",
|
||||||
"tsup": "^8.4.0",
|
"tsup": "^8.4.0",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vitest": "^3.0.8"
|
"vitest": "^3.0.8"
|
||||||
|
|
|
@ -128,6 +128,7 @@ describe('Basic', () => {
|
||||||
({ children }) => {
|
({ children }) => {
|
||||||
return (
|
return (
|
||||||
<html>
|
<html>
|
||||||
|
<head></head>
|
||||||
<body>{children}</body>
|
<body>{children}</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
|
@ -139,7 +140,9 @@ describe('Basic', () => {
|
||||||
const res = await app.request('/')
|
const res = await app.request('/')
|
||||||
expect(res).not.toBeNull()
|
expect(res).not.toBeNull()
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(await res.text()).toBe('<!DOCTYPE html><html><body><h1>Hello</h1></body></html>')
|
expect(await res.text()).toBe(
|
||||||
|
'<!DOCTYPE html><html><head></head><body><h1>Hello</h1></body></html>'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should return a content without a doctype', async () => {
|
it('Should return a content without a doctype', async () => {
|
||||||
|
@ -161,7 +164,7 @@ describe('Basic', () => {
|
||||||
const res = await app.request('/')
|
const res = await app.request('/')
|
||||||
expect(res).not.toBeNull()
|
expect(res).not.toBeNull()
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(await res.text()).toBe('<html><body><h1>Hello</h1></body></html>')
|
expect(await res.text()).toBe('<html><head></head><body><h1>Hello</h1></body></html>')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should return a custom doctype', async () => {
|
it('Should return a custom doctype', async () => {
|
||||||
|
@ -187,7 +190,7 @@ describe('Basic', () => {
|
||||||
expect(res).not.toBeNull()
|
expect(res).not.toBeNull()
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(await res.text()).toBe(
|
expect(await res.text()).toBe(
|
||||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><body><h1>Hello</h1></body></html>'
|
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><head></head><body><h1>Hello</h1></body></html>'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -231,6 +234,8 @@ describe('Streaming', () => {
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(res.headers.get('Transfer-Encoding')).toBe('chunked')
|
expect(res.headers.get('Transfer-Encoding')).toBe('chunked')
|
||||||
expect(res.headers.get('Content-Type')).toBe('text/html; charset=UTF-8')
|
expect(res.headers.get('Content-Type')).toBe('text/html; charset=UTF-8')
|
||||||
expect(await res.text()).toBe('<!DOCTYPE html><html><body><h1>Hello</h1></body></html>')
|
expect(await res.text()).toBe(
|
||||||
|
'<!DOCTYPE html><html><head></head><body><h1>Hello</h1></body></html>'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,10 +30,11 @@ const createRenderer =
|
||||||
options?: RendererOptions
|
options?: RendererOptions
|
||||||
) =>
|
) =>
|
||||||
async (children: React.ReactElement, props?: Props) => {
|
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) {
|
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(
|
const stream = await renderToReadableStream(
|
||||||
React.createElement(RequestContext.Provider, { value: c }, node),
|
React.createElement(RequestContext.Provider, { value: c }, node),
|
||||||
options.readableStreamOptions
|
options.readableStreamOptions
|
||||||
|
@ -52,8 +53,8 @@ const createRenderer =
|
||||||
typeof options?.docType === 'string'
|
typeof options?.docType === 'string'
|
||||||
? options.docType
|
? options.docType
|
||||||
: options?.docType === false
|
: options?.docType === false
|
||||||
? ''
|
? ''
|
||||||
: '<!DOCTYPE html>'
|
: '<!DOCTYPE html>'
|
||||||
const body =
|
const body =
|
||||||
docType + renderToString(React.createElement(RequestContext.Provider, { value: c }, node))
|
docType + renderToString(React.createElement(RequestContext.Provider, { value: c }, node))
|
||||||
return c.html(body)
|
return c.html(body)
|
||||||
|
@ -71,7 +72,7 @@ export const reactRenderer = (
|
||||||
if (component) {
|
if (component) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
c.setLayout((props: any) => {
|
c.setLayout((props: any) => {
|
||||||
return component({ ...props, Layout, c }, c)
|
return component({ ...props, Layout, c })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.setRenderer(createRenderer(c, Layout, component, options))
|
c.setRenderer(createRenderer(c, Layout, component, options))
|
||||||
|
|
61
yarn.lock
61
yarn.lock
|
@ -2197,18 +2197,18 @@ __metadata:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@arethetypeswrong/cli": "npm:^0.17.4"
|
"@arethetypeswrong/cli": "npm:^0.17.4"
|
||||||
"@cloudflare/vitest-pool-workers": "npm:^0.7.8"
|
"@cloudflare/vitest-pool-workers": "npm:^0.7.8"
|
||||||
"@types/react": "npm:^18"
|
"@types/react": "npm:^19.1.0"
|
||||||
"@types/react-dom": "npm:^18.2.17"
|
"@types/react-dom": "npm:^19.1.2"
|
||||||
publint: "npm:^0.3.9"
|
publint: "npm:^0.3.9"
|
||||||
react: "npm:^18.2.0"
|
react: "npm:^19.1.0"
|
||||||
react-dom: "npm:^18.2.0"
|
react-dom: "npm:^19.1.0"
|
||||||
tsup: "npm:^8.4.0"
|
tsup: "npm:^8.4.0"
|
||||||
typescript: "npm:^5.8.2"
|
typescript: "npm:^5.8.2"
|
||||||
vitest: "npm:^3.0.8"
|
vitest: "npm:^3.0.8"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
hono: "*"
|
hono: "*"
|
||||||
react: "*"
|
react: ^19.0.0
|
||||||
react-dom: "*"
|
react-dom: ^19.0.0
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
@ -3924,12 +3924,12 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/react-dom@npm:^18.2.17":
|
"@types/react-dom@npm:^19.1.2":
|
||||||
version: 18.3.5
|
version: 19.1.2
|
||||||
resolution: "@types/react-dom@npm:18.3.5"
|
resolution: "@types/react-dom@npm:19.1.2"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@types/react": ^18.0.0
|
"@types/react": ^19.0.0
|
||||||
checksum: b163d35a6b32a79f5782574a7aeb12a31a647e248792bf437e6d596e2676961c394c5e3c6e91d1ce44ae90441dbaf93158efb4f051c0d61e2612f1cb04ce4faa
|
checksum: 100c341cacba9ec8ae1d47ee051072a3450e9573bf8eeb7262490e341cb246ea0f95a07a1f2077e61cf92648f812a0324c602fcd811bd87b7ce41db2811510cd
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -3943,6 +3943,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@types/request@npm:^2.48.8":
|
||||||
version: 2.48.12
|
version: 2.48.12
|
||||||
resolution: "@types/request@npm:2.48.12"
|
resolution: "@types/request@npm:2.48.12"
|
||||||
|
@ -11882,15 +11891,14 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-dom@npm:^18.2.0":
|
"react-dom@npm:^19.1.0":
|
||||||
version: 18.3.1
|
version: 19.1.0
|
||||||
resolution: "react-dom@npm:18.3.1"
|
resolution: "react-dom@npm:19.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: "npm:^1.1.0"
|
scheduler: "npm:^0.26.0"
|
||||||
scheduler: "npm:^0.23.2"
|
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18.3.1
|
react: ^19.1.0
|
||||||
checksum: a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85
|
checksum: 3e26e89bb6c67c9a6aa86cb888c7a7f8258f2e347a6d2a15299c17eb16e04c19194e3452bc3255bd34000a61e45e2cb51e46292392340432f133e5a5d2dfb5fc
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -11903,6 +11911,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"read-yaml-file@npm:^1.1.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "read-yaml-file@npm:1.1.0"
|
resolution: "read-yaml-file@npm:1.1.0"
|
||||||
|
@ -12610,12 +12625,10 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"scheduler@npm:^0.23.2":
|
"scheduler@npm:^0.26.0":
|
||||||
version: 0.23.2
|
version: 0.26.0
|
||||||
resolution: "scheduler@npm:0.23.2"
|
resolution: "scheduler@npm:0.26.0"
|
||||||
dependencies:
|
checksum: 5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356
|
||||||
loose-envify: "npm:^1.1.0"
|
|
||||||
checksum: 26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue