Skip to content

Commit 58825a7

Browse files
authored
feat(jsx-renderer): support function-based options (#4780)
1 parent 0e80acb commit 58825a7

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

src/middleware/jsx-renderer/index.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,62 @@ d.replaceWith(c.content)
407407
expect(await res.text()).toBe('<!DOCTYPE html><div>Hi</div>')
408408
})
409409

410+
it('Should accept function-based options', async () => {
411+
type Env = { Bindings: { HONO_STREAMING?: boolean } }
412+
const app = new Hono<Env>()
413+
414+
const Component = async () => {
415+
return <div>Component</div>
416+
}
417+
418+
app.use(
419+
'*',
420+
jsxRenderer<Env>(
421+
({ children }) => {
422+
return (
423+
<html>
424+
<body>{children}</body>
425+
</html>
426+
)
427+
},
428+
(c) => {
429+
expectTypeOf(c.env?.HONO_STREAMING).toEqualTypeOf<boolean | undefined>()
430+
return { docType: true, stream: c.env?.HONO_STREAMING ?? true }
431+
}
432+
)
433+
)
434+
435+
app.get('/', async (c) => {
436+
return c.render(
437+
<div>
438+
<Suspense fallback={'loading...'}>
439+
<Component />
440+
</Suspense>
441+
</div>,
442+
{ title: 'Suspense test' }
443+
)
444+
})
445+
446+
const resStream = await app.request('/')
447+
expect(resStream.status).toBe(200)
448+
expect(resStream.headers.get('Transfer-Encoding')).toBe('chunked')
449+
const textStream = await resStream.text()
450+
expect(textStream).toContain('<template')
451+
expect(textStream).toContain('<script')
452+
expect(textStream).toContain('loading...')
453+
454+
const resNotStream = await app.request('/', undefined, { HONO_STREAMING: false })
455+
expect(resNotStream.status).toBe(200)
456+
expect(resNotStream.headers.get('Transfer-Encoding')).toBeNull()
457+
const textNotStream = await resNotStream.text()
458+
expect(textNotStream).not.toContain('<template')
459+
expect(textNotStream).not.toContain('<script')
460+
expect(textNotStream).not.toContain('loading...')
461+
expect(textNotStream).toBe(
462+
'<!DOCTYPE html><html><body><div><div>Component</div></div></body></html>'
463+
)
464+
})
465+
410466
describe('keep context status', async () => {
411467
it('Should keep context status', async () => {
412468
const app = new Hono()

src/middleware/jsx-renderer/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ type ComponentWithChildren = (
3131
) => HtmlEscapedString | Promise<HtmlEscapedString>
3232

3333
const createRenderer =
34-
(c: Context, Layout: FC, component?: Component, options?: RendererOptions) =>
34+
(
35+
c: Context,
36+
Layout: FC,
37+
component?: Component,
38+
options?: RendererOptions | ((c: Context) => RendererOptions)
39+
) =>
3540
(children: JSXNode, props: PropsForRenderer) => {
41+
options = typeof options === 'function' ? options(c) : options
3642
const docType =
3743
typeof options?.docType === 'string'
3844
? options.docType
@@ -107,9 +113,9 @@ const createRenderer =
107113
* })
108114
* ```
109115
*/
110-
export const jsxRenderer = (
116+
export const jsxRenderer = <E extends Env = Env>(
111117
component?: ComponentWithChildren,
112-
options?: RendererOptions
118+
options?: RendererOptions | ((c: Context<E>) => RendererOptions)
113119
): MiddlewareHandler =>
114120
function jsxRenderer(c, next) {
115121
const Layout = (c.getLayout() ?? Fragment) as FC

0 commit comments

Comments
 (0)