hono-jsx-router
v1.5.0
Published
A file-based router for Hono.js with the JSX middleware.
Downloads
42
Readme
JSXRouter
JSXRouter
is a file-based router for Hono.js with the JSX middleware.
Table of Contents
Installation
npm i --save hono-jsx-router
Usage
import { Hono } from 'hono';
import { JSXRouter } from 'hono-jsx-router';
const jsxRouter: JSXRouter<any> = new JSXRouter({
config: {
// JSXRouter config
}
});
const app = new Hono({
router: jsxRouter
});
jsxRouter.applyRoutes();
Config
package.json
:
{
//...
"scripts": {
"build": "npx jsx-combine"
},
"dependencies": {
"hono": "^3.2.0",
"hono-jsx-router": "^1.3.0"
},
"jsxRouter": {
"path": "src/routes"
}
}
index.ts
:
import { Hono } from 'hono';
import { JSXRouter } from 'hono-jsx-router';
const jsxRouter: JSXRouter<any> = new JSXRouter({
config: {
layout: {
// layout config
props: {
// props that can be passed to layouts
}
},
page: {
// page config
props: {
// props that can be passed to pages
}
}
}
});
const app = new Hono({
router: jsxRouter
});
jsxRouter.applyRoutes();
The props
object can take strings or functions as values. If the value is a function, the Context object is passed to it.
Pages
In the directory configured as path
in your package.json
, place JSX files (.tsx
). If you configure path
to be ./src/routes
, then JSXRouter will serve the files found there, The names should reflect the desired route. For example, if you have a file called about.tsx
, and you are using JSXRouter at /
of your site, this file will be served at /about
.
Subfolders
You can have multiple folders as needed, for when you need multiple subpages under /about
, you can create an about
folder and put as many subpages there that you need.
Wildcards
You can also add files that has a wildcard in its name to catch all routes that aren't handled by sibling files. So you can have a directory structure like:
src/routes/about/
./index.tsx
./other_page.tsx
./*.tsx
You will end up with routes to /about/
, /about/other_page/
, and /about/*
. The wildcard does not override the other two routes here.
Layout
You can provide a common layout in a file called _layout.tsx
. This will be used to wrap every page in the directory. Here is an example layout:
import { html } from 'hono/html';
export default (props: { children?: any }) => {
return html`<!DOCTYPE html>
<html lang="EN-US">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="lightgray" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="gray" />
<title>Example Site</title>
<link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" />
</head>
<body>${props.children}</body>
</html>`;
};
It is recommended to create a components
directory alongside your routes
directory, placing JSX files there to be imported into your pages. For example, say you have src/components/Header.tsx
, it could contain something like this:
export default (props: { children?: any }) => {
return (
<header>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/blog">Blog</a>
</header>
)
}
Then you can use it in a page, like src/routes/index.tsx
:
import Header from '../components/Header';
export default (props: {}) => {
return (<>
<Header />
<h1>Home</h1>
<p>Hello world!</p>
</>)
};
Context
Each page has access to Hono's Context object via props
. Declare it like this to use it:
import type { Context } from 'hono';
export default (props: { c: Context }) => {
// ...
};
Fallback Routers
When using the basic import of JSXRouter, it will use Hono's LinearRouter to handle routes not found in the file structure. You can pick a different router depending on your use case by importing from one of the presets:
- LinearRouter:
import { JSXRouter } from 'hono-jsx-router/linear';
- PatternRouter:
import { JSXRouter } from 'hono-jsx-router/pattern';
- RegExpRouter:
import { JSXRouter } from 'hono-jsx-router/reg-exp';
- SmartRouter*:
import { JSXRouter } from 'hono-jsx-router/smart';
- TrieRouter:
import { JSXRouter } from 'hono-jsx-router/trie';
*When using the SmartRouter, you will need to specify the routers it should pick from:
import { Hono } from 'hono';
import { JSXRouter } from 'hono-jsx-router/smart';
const jsxRouter: JSXRouter<any> = new JSXRouter({
config: {
// JSXRouter config
},
routers: [
new RegExpRouter(),
new TrieRouter()
]
});
Query Parameters
A JSX page can receive query parameters. To access them, add params
to your props
argument, like below:
export default (props: { params:? Record<string, string[]> }) => {
//...
};
Then you can access the query parameters anywhere in the page. For example, if a user browses to /?foo=bar&abc=xyz
, you can access these query parameters like so:
export default (props: { params:? Record<string, string[]> }) => {
return (<>
<h1>Home</h1>
<p>Hello world!</p>
<p>You query for foo is {props.params.foo[0]} and your query for abc is {props.params.abc[0]}.</p>
</>)
};
This will result in the following HTML:
<h1>Home</h1>
<p>Hello world!</p>
<p>You query for foo is bar and your query for abc is xyz.</p>
Since the params are string arrays (string[]
), if there are multiple instances of a key in a query, all of the values can be accessed in order by index. Internally, this uses HonoRequest.queries()
.
Known Issues
- Need to add a way to set per page
<head>
attributes. - Subfolder layouts are not currently supported, but is a planned feature.