1.5.0 • Published 11 months ago

hono-jsx-router v1.5.0

Weekly downloads
-
License
MIT
Repository
gitlab
Last release
11 months ago

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.
1.5.0

11 months ago

1.4.0

11 months ago

1.3.1

11 months ago

1.3.0

11 months ago

1.2.0

11 months ago

1.1.1

11 months ago

1.1.1-alpha8

11 months ago

1.1.1-alpha7

11 months ago

1.1.1-alpha6

11 months ago

1.1.1-alpha5

11 months ago

1.1.1-alpha4

11 months ago

1.1.1-alpha3

11 months ago

1.1.1-alpha2

11 months ago

1.1.1-alpha1

11 months ago

1.1.0

11 months ago

1.0.0-alpha11

11 months ago

1.0.0-alpha10

11 months ago

1.0.0-alpha9

11 months ago

1.0.0-alpha8

11 months ago

1.0.0-alpha7

11 months ago

1.0.0-alpha6

11 months ago

1.0.0-alpha5

11 months ago

1.0.0-alpha4

11 months ago

1.0.0-alpha3

11 months ago

1.0.0-alpha2

11 months ago

1.0.0-alpha1

11 months ago

1.0.0

11 months ago