Open Code-Hex opened 8 months ago
Hi @Code-Hex !
How about this approach? This way, the template
has a type (A
| B
) and the implementation of the handler is clean.
// renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
export type Template = 'A' | 'B'
declare module 'hono' {
interface ContextRenderer {
(content: string | Promise<string>, props?: { title?: string; template: Template }): Response
}
}
export const renderer = jsxRenderer(({ children, template }) => {
if (template === 'A') {
return (
<html>
<body>
<h1>Template A</h1>
{children}
</body>
</html>
)
}
if (template === 'B') {
return (
<html>
<body>
<h1>Template B</h1>
{children}
</body>
</html>
)
}
return (
<html>
<body>
<h1>Template Default</h1>
{children}
</body>
</html>
)
})
// index.tsx
import { Hono } from 'hono'
import { renderer, type Template } from './renderer'
const app = new Hono()
app.get('*', renderer)
app.get('/', (c) => {
const template = c.req.query('template') as Template | undefined
if (template === 'A') {
return c.render(<h1>Hello!</h1>, {
template: 'A'
})
}
if (template === 'B') {
return c.render(<h1>Hello!</h1>, {
template: 'B'
})
}
return c.render(<h1>Hello!</h1>)
})
export default app
@yusukebe The problem with that approach, as described in the description, is that it cannot handle branching when each template has different props.
For example, template A might have only a title, while B might have name, items, and so on. The concept is something like the following code (I think it can be written more cleanly):
const jsxRendererWithName<Tmpls extends Record<string, any>> = (
templates: Tmpls,
component?: FC<PropsWithChildren<PropsForRenderer & { Layout: FC }>>,
options?: unknown
): MiddlewareHandler => { ... }
// --- User Side
type Templates = {
A: { title: string };
B: { name: string; items: any[] };
}
type TemplatesKey = keyof Templates;
declare module 'hono' {
interface ContextRenderer {
<K extends TemplatesKey, P extends Templates[K]>(
name: K,
content: string | Promise<string>,
props: P,
): Response | Promise<Response>;
}
}
app.get("/", async(c) => {
c.render("A", <div></div>, { title: ""})
c.render("B", <div></div>, {name: "aa", items: []})
})
The problem with that approach, as described in the description, is that it cannot handle branching when each template has different props.
Ah, I see. I can't give you an answer right now, but I am trying to think of a good way to do it!
What is the feature you are proposing?
Hello! 👋
I propose providing a middleware for
jsxRendererWithName(name: string, component, options)
and an API likec.renderWithName(name, <h1>Hello, World!</h1>)
.This would be useful in cases where we want to create multiple layouts within a single application.
Currently, I believe
jsxRenderer
is designed to handle only one template. As a workaround to enable the above case, we would have to dynamically switch the rendering content based on the request path from the context. However, this approach leads to the problem of extending the values passed as options for each template.I believe this proposal can solve these issues.
https://hono.dev/middleware/builtin/jsx-renderer