Tags English

Blog - Yusuke Wada

Screenshot

Hono CLI の紹介

#Hono

この記事は英語で書かれた原文をAIが翻訳したものです。

Hono CLI の紹介

Honoはこれまで数々の革新的な機能を提供してきました。正規表現を活用したルーター、軽量なサーバーサイドJSX、TypeScriptの型によるRPC、Web Standardsを使ったマルチランタイム対応。アイデアと実装で世界と戦ってきました。

今日はHono CLIを紹介します。

Hono CLIはまったく新しいコンセプトのコマンドラインインターフェースです。

これは人間とAIのためのCLIです。インストールするとhonoコマンドが使えるようになります。

hono --help

サブコマンドは5つあります。

ひとつずつ見ていきましょう。

hono docs

まずはhono docsです。次のように実行します。

hono docs [path]

pathにはHonoのWebサイト(https://hono.dev)のパスを指定します。たとえば「[Routing](https://hono.dev/docs/api/routing)」のページを見たい場合はこうします。

hono docs /docs/api/routing

これでドキュメントを閲覧できます。

「それだけ?」と思うかもしれません。はい、それだけです。ただしポイントは、Markdownが標準出力に出力されることです。

Terminal

もうお分かりでしょう。これはAIフレンドリーなのです。Webページを取得したときについてくるHTMLタグがありません。標準出力なので、AIコーディングエージェントが読めます。

次はhono searchです。

hono search <query>

queryには検索語を指定します。たとえばミドルウェアに関するドキュメントを探すにはこうします。

hono search middleware

これはWebサイト内の関連ページのURLとパスをJSON形式で標準出力に出力します。

Terminal

つまり、hono docsと組み合わせれば「AIが自律的にドキュメントを検索して読む」ことができるのです。たとえばBasic認証についてのドキュメントを検索して読むには、次のような流れになります。

AI向けのコマンドはまだあります。次に進みましょう。

hono request

次のコマンドはhono requestです。

hono request [file]

fileのデフォルト値はsrc/index.tsですが、明示的に指定するならこうです。

hono request src/index.ts

このコマンドを理解するには、まずHonoのapp.request() APIを思い浮かべてください。app.request()を使うと、サーバーを立てることなくHonoアプリにリクエストを送ってレスポンスを得ることができます。これは動作確認やテストにとても便利です。

パス/にGETリクエストを送り、返ってきたResponseオブジェクトがresに入るコードです。

const res = await app.request('/')

hono requestは、コマンドラインで指定したリクエストを、指定したファイル内のHonoアプリに送り、結果を出力します。

hono request src/index.ts

これは以下を実行します。

const res = await app.request('/')

たとえば、こんなHello Worldアプリがあるとします。

// src/index.ts
import { Hono } from 'hono'

const app = new Hono()
app.get('/', (c) => c.text('Hello World'))

export default app

このファイルに対してhono requestを実行してみましょう。

Terminal

-Pはリクエストするパス/を指定します。デフォルトのメソッドはGETです。標準出力には「ステータスコードは200、ボディはHello World」という結果がJSON形式で出力されます。もっと複雑なこともできます。curlのように、-Xでメソッドを、-dでボディを指定できます。

hono request \
  -P /api/users \
  -X POST \
  -d '{"name":"Alice"}' \
  src/index.ts

このコマンドは人間にとってもとても便利です。これまでアプリをテストするときは、Wrangler、Deno、Bun、Node.jsのコマンドでサーバーを立ち上げて、Webブラウザやcurlで叩いていました。でもhono requestなら、サーバーを立てずにアプリをテストできるのです!

AIも使えます。これは非常に強力です。コーディングエージェントがサーバーを立ち上げてcurlを実行するのを見たことがあるでしょう。そして、サーバーをうまく終了できずにポートが衝突したり、サーバーを何個も立ち上げてしまったりするのも見たことがあるはずです…。hono requestならサーバーを立てる必要すらないので、非常に速く、正確に、クリーンにアプリをテストできます。

そしてAIは、このコマンドを先の2つのコマンドと組み合わせることができます。

このワークフローはAGENTS.mdCLAUDE.mdにステップとして書けます。これはそのまま動きます。

# My App Development Guidelines

## Hono Development

Use the `hono` CLI for efficient development. View all commands with `hono --help`.

### Core Commands

- **`hono docs [path]`** - Browse Hono documentation
- **`hono search <query>`** - Search documentation
- **`hono request [file]`** - Test app requests without starting a server

### Quick Examples

```bash
# Search for topics
hono search middleware
hono search "getting started"

# View documentation
hono docs /docs/api/context
hono docs /docs/guides/middleware

# Test your app
hono request -P /api/users src/index.ts
hono request -P /api/users -X POST -d '{"name":"Alice"}' src/index.ts
```

### Workflow

1. Search documentation: `hono search <query>`
2. Read relevant docs: `hono docs [path]`
3. Test implementation: `hono request [file]`

デモをご覧ください。コーディングエージェントがhonoコマンドを使ってアプリを作っている様子が分かります。

Demo

hono serve

ここまではAIのためのコマンドでした。次は人間のためのコマンドを紹介します。まずはhono serveです。

hono serve index.ts

これはindex.tsのHonoアプリをhttp://localhost:7070で起動します。

?? それだけ?? Node.js Adapterが要らなくなるだけでは?WranglerやDeno、Bunでも同じことができるのでは?

いいえ、--useオプションがあるのです。app.use()を思い浮かべてください。

app.use(middleware)

app.use()はアプリにミドルウェアを適用します。たとえばビルトインのloggerミドルウェアはこう使います。

app.use(logger())

そこからlogger()だけを取り出します。hono serveでは、それを--useオプションの値として指定でき、アプリのコードを変更することなくミドルウェアを適用できます。

hono serve --use 'logger()' src/index.ts

こうすれば、loggerを指定していないアプリでもログを出力するようになります。

Terminal

これを応用すれば、コードを書き換えることなくBasic認証を追加することだってできます。

hono serve \
 --use "logger()" \
 --use "basicAuth({username:'foo',password:'bar'})" \
  src/index.ts

さて、このサブコマンドにsrc/index.tsのようなエントリーパスを渡さない場合は、空のアプリが使われます。

Terminal

http://localhost:7070にアクセスすると404が返ります。これを応用すると、ローカルにファイルがなくても、ミドルウェアを組み合わせたサーバーを立ち上げることができます。

たとえば、ローカルファイルを配信するサーバーを立てられます。

hono serve \
 --use "serveStatic({root:'./'})"

ヘルパーも使えるので、Proxyヘルパーのproxyを使って、Ramen APIへのリバースプロキシを立てることもできます。

hono serve \
 --use '(c) => proxy(`https://ramen-api.dev${new URL(c.req.url).pathname}`)'

hono optimize

最後のコマンドはhono optimizeです。

hono optimize [entry]

コマンドの説明の前に、Honoのルーターの話をしましょう。RegExpRouterはJavaScriptの世界で最速クラスのルーターです。特定の条件下では最速です。RegExpRouterのアイデアは、動的なルート情報をひとつの大きな正規表現にまとめ、リクエストが来たら一発でマッチさせるというものです。これには弱点があります。

  1. 初期化が遅い
  2. ファイルサイズが大きい

これらを解決するため、Honoでは2つのルーターが考案され、プリセットとして提供されています。

  1. LinearRouter - hono/quick
  2. PatternRouter - hono/tiny

たしかに、LinearRouterは初期化を含むベンチマークで速く、PatternRouterはバンドルサイズが小さい。でも、RegExpRouterを使いたい!

そこで今日は7番目のルーター(既存の6つは現行の5つのルーターと、非推奨になったStaticRouter)を紹介します。PreparedRegExpRouterです。

PreparedRegExpRouterのアイデアは、RegExpRouterが作る正規表現に相当するルート情報を、事前に文字列に変換してハードコードしてしまうというものです。

こんなアプリがあるとします。

import { Hono } from 'hono'

const app = new Hono()

app.get('/posts', (c) => c.json({}))
app.get('/posts/:id', (c) => c.json({}))
app.put('/posts', (c) => c.json({}))

export default app

このルート情報を事前に文字列に変換し、ルーターのコンストラクタに渡します。

const routerParams = [
  { ALL: [/^\/posts\/([^/]+)$()/, [0, 0, []], { '/posts': [[], []] }] },
  { '/posts': [[['']]], '/posts/:id': [[[2], { id: 1 }]] }
]
const router = new PreparedRegExpRouter(...routerParams)

これでまず初期化が速くなります。初期化を含めたルーター性能を測ったベンチマーク結果を見てみましょう。

Benchmark

これをソートすると…

Benchmark

LinearRouterが1位なのは当然として、PreparedRegExpRouterが2位につけています。RegExpRouterはずっと後ろです。RegExpRouterと比較すると、PreparedRegExpRouterは16.5倍速い(初期化を含むベンチマークにおいて)ことになります。

Hono CLIの話に戻りましょう。

hono optimizeは「あなたのアプリに合わせてHonoを最適化」します。では最適化されたHonoとは何か?これです。

class Hono extends HonoBase {
  constructor(options = {}) {
    super(options)
    const routerParams = [
      { ALL: [/^\/posts\/([^/]+)$()/, [0, 0, []], { '/posts': [[], []] }] },
      { '/posts': [[['']]], '/posts/:id': [[[2], { id: 1 }]] }
    ]
    this.router = new PreparedRegExpRouter(...routerParams)
  }
}

つまり、その特定のアプリのためにPreparedRegExpRouterが実装されたHonoになるのです。

hono optimizeを実行してみましょう。

Terminal

src/index.tsを最適化した結果がdist/index.jsに書き出されます。そのままwrangler deployで直接デプロイできます。

hono optimize src/index.ts
wrangler deploy dist/index.js

では、どれくらい小さくなったのでしょうか?最適化なしでminifyしたビルド、minifyオプション付きでhono optimizeを実行したファイル、hono/tinyプリセットを使ったものを比較してみます。

Compare

hono/tinyのサイズには及ばないものの、元のアプリの18.0KBと比べると11.14KBと大幅に小さくなっています。38%の削減です。

つまり、hono optimizeはアプリをより速く、より小さくします。このように、Hono CLIは人間のためのシンプルなサブコマンド、hono servehono optimizeを提供します。

Note: PreparedRegExpRouterを使ったこの最適化手法は、将来的にはVite buildプラグインなどのビルド・バンドルツールでも使えるようにしたいと考えています。

まとめ

Hono CLIは5つのサブコマンドを提供します。

  1. hono docs
  2. hono search
  3. hono request
  4. hono serve
  5. hono optimize

これらは人間とAIのためのコマンドです。

Hono CLIのリポジトリは公開されています。

https://github.com/honojs/cli

そして、Hono CLIは今すぐ試せます。

npm i @hono/cli

Enjoy!