diff --git a/src/middleware/jsx/README.md b/src/middleware/jsx/README.md index 8a2ff89a..2974978b 100644 --- a/src/middleware/jsx/README.md +++ b/src/middleware/jsx/README.md @@ -2,7 +2,7 @@ JSX Middleware enable rendering HTML with JSX syntax. It's just for Sever-Side-Rendering. No virtual DOM. -This middleware supports only for TypeScript. +This middleware is only for writing with TypeScript. ## Settings @@ -12,7 +12,8 @@ tsconfig.json: { "compilerOptions": { "jsx": "react", - "jsxFactory": "h" + "jsxFactory": "jsx", + "jsxFragmentFactory": "Fragment" } } ``` @@ -23,12 +24,10 @@ index.tsx: ```tsx import { Hono } from 'hono' -import { h, jsx } from 'hono/jsx' +import { jsx } from 'hono/jsx' const app = new Hono() -app.use('*', jsx()) - const Layout = (props: { children?: string }) => { return ( @@ -52,7 +51,7 @@ const Top = (props: { messages: string[] }) => { app.get('/', (c) => { const messages = ['Good Morning', 'Good Evening', 'Good Night'] - return c.render() + return c.htm() }) app.fire() @@ -60,13 +59,47 @@ app.fire() ## dangerouslySetInnerHTML +`dangerouslySetInnerHTML` allows you to set HTML directly. + ```tsx app.get('/foo', (c) => { - const html = { __html: 'JSX · SSR' } - return c.render(
) + const inner = { __html: 'JSX · SSR' } + const Div =
}) ``` +## memo + +You can memorize calculated strings of the component with `memo`. + +```tsx +import { jsx, memo } from 'hono/jsx' + +const Header = memo(() =>
Welcome to Hono
) +const Footer = memo(() =>
Powered by Hono
) +const Layout = ( +
+
+

Hono is cool!

+
+
+) +``` + +## Fragment + +```tsx +import { jsx, Fragment } from 'hono/jsx' + +const List = () => ( + +

first child

+

second child

+

third child

+
+) +``` + ## Tips for Cloudflare Workers It's useful to use Miniflare's`live-reload` option for developing. diff --git a/src/middleware/jsx/index.test.tsx b/src/middleware/jsx/index.test.tsx index eb5c3a41..6ac397a5 100644 --- a/src/middleware/jsx/index.test.tsx +++ b/src/middleware/jsx/index.test.tsx @@ -1,18 +1,17 @@ import { Hono } from '../../hono' -import { h, jsx, memo, Fragment } from '.' +import { jsx, memo, Fragment } from '.' describe('JSX middleware', () => { const app = new Hono() - app.use('*', jsx()) it('Should render HTML strings', async () => { app.get('/', (c) => { - return c.render(

Hello

) + return c.html(

Hello

) }) const res = await app.request('http://localhost/') expect(res.status).toBe(200) 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/src/middleware/jsx/index.ts b/src/middleware/jsx/index.ts index 3e3254cf..b65ee934 100644 --- a/src/middleware/jsx/index.ts +++ b/src/middleware/jsx/index.ts @@ -1,28 +1,16 @@ -import type { Context } from '../../context' -import type { Next } from '../../hono' import { escape } from '../../utils/html' import type { HtmlEscapedString } from '../../utils/html' declare global { // eslint-disable-next-line @typescript-eslint/no-namespace - namespace h.JSX { + namespace jsx.JSX { interface IntrinsicElements { [tagName: string]: Record } } } -export const jsx = () => { - return async (c: Context, next: Next) => { - c.render = (content: string) => { - const output = `${content.toString()}` - return c.html(output) - } - await next() - } -} - -export const h = ( +export const jsx = ( tag: string | Function, props: Record, ...children: (string | HtmlEscapedString)[] @@ -116,5 +104,5 @@ export const memo = ( } export const Fragment = (props: { key?: string; children?: any }): HtmlEscapedString => { - return h('', {}, ...(props.children || [])) + return jsx('', {}, ...(props.children || [])) } diff --git a/tsconfig.json b/tsconfig.json index 2d1cffa0..e36422a6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,7 @@ "@cloudflare/workers-types" ], "jsx": "react", - "jsxFactory": "h", + "jsxFactory": "jsx", "jsxFragmentFactory": "Fragment", }, "include": [