@hono/react-renderer
v0.2.1
Published
React Renderer Middleware for Hono
Downloads
2,867
Readme
React Renderer Middleware
React Renderer Middleware allows for the easy creation of a renderer based on React for Hono.
Installation
npm i @hono/react-renderer react react-dom hono
npm i -D @types/react @types/react-dom
Settings
tsconfig.json
:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
}
}
If you are using Vite, add ssr external
config to vite.config.ts
:
import build from '@hono/vite-cloudflare-pages'
import devServer from '@hono/vite-dev-server'
import adapter from '@hono/vite-dev-server/cloudflare'
import { defineConfig } from 'vite'
export default defineConfig({
ssr: {
external: ['react', 'react-dom'], // <== add
},
plugins: [
build(),
devServer({
adapter,
entry: 'src/index.tsx',
}),
],
})
Usage
Basic
import { Hono } from 'hono'
import { reactRenderer } from '@hono/react-renderer'
const app = new Hono()
app.get(
'*',
reactRenderer(({ children }) => {
return (
<html>
<body>
<h1>React + Hono</h1>
<div>{children}</div>
</body>
</html>
)
})
)
app.get('/', (c) => {
return c.render(<p>Welcome!</p>)
})
Extending Props
You can define types of Props
:
declare module '@hono/react-renderer' {
interface Props {
title: string
}
}
Then, you can use it in the reactRenderer()
function and pass values as a second argument to c.render()
:
app.get(
'*',
reactRenderer(({ children, title }) => {
return (
<html>
<head>
<title>{title}</title>
</head>
<body>
<div>{children}</div>
</body>
</html>
)
})
)
app.get('/', (c) => {
return c.render(<p>Welcome!</p>, {
title: 'Top Page',
})
})
useRequestContext()
You can get an instance of Context
in a function component:
const Component = () => {
const c = useRequestContext()
return <p>You access {c.req.url}</p>
}
app.get('/', (c) => {
return c.render(<Component />)
})
Options
docType
If you set it true
, DOCTYPE
will be added:
app.get(
'*',
reactRenderer(
({ children }) => {
return (
<html>
<body>
<div>{children}</div>
</body>
</html>
)
},
{
docType: true,
}
)
)
The HTML is the following:
<!DOCTYPE html>
<html>
<body>
<div><p>Welcome!</p></div>
</body>
</html>
You can specify the docType
as you like.
app.get(
'*',
reactRenderer(
({ children }) => {
return (
<html>
<body>
<div>{children}</div>
</body>
</html>
)
},
{
docType:
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
}
)
)
stream
It enables returning a streaming response. You can use a Suspense
with it:
import { reactRenderer } from '@hono/react-renderer'
import { Suspense } from 'react'
app.get(
'*',
reactRenderer(
({ children }) => {
return (
<html>
<body>
<div>{children}</div>
</body>
</html>
)
},
{
stream: true,
}
)
)
let done = false
const Component = () => {
if (done) {
return <p>Done!</p>
}
throw new Promise((resolve) => {
done = true
setTimeout(resolve, 1000)
})
}
app.get('/', (c) => {
return c.render(
<Suspense fallback='loading...'>
<Component />
</Suspense>
)
})
Limitation
A streaming feature is not available on Vite or Vitest.
Author
Yusuke Wada https://github.com/yusukebe
License
MIT