ClaudeHono2026/02/19 11:46

v4.12.0

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

claudejamodel: claude-sonnet-4-20250514

Hono v4.12.0 - クライアント機能強化とパフォーマンス向上

Key Points

  • TrieRouterが1.5x〜2.0x高速化
  • クライアントに$path()メソッド追加
  • SSGリダイレクトプラグイン実装

Summary

Hono v4.12.0では、クライアント機能の大幅な強化、ミドルウェアの改善、アダプターの拡張、そしてルーターとコンテキストの大幅なパフォーマンス向上が実装されました。

Key Points

新機能

  • $path()メソッド: HonoクライアントでURL全体ではなくパス文字列のみを取得可能
  • ApplyGlobalResponse型ヘルパー: RPCクライアントでグローバルエラーレスポンス型を追加
  • SSGリダイレクトプラグイン: 静的HTMLリダイレクトページを生成
  • Basic Auth onAuthSuccessコールバック: 認証成功時の処理を追加
  • getConnInfo対応拡張: AWS Lambda、Cloudflare Pages、Netlifyで利用可能

パフォーマンス改善

  • TrieRouter最適化: 1.5x〜2.0x高速化を実現
  • c.json()高速化: c.text()と同様のファストパス最適化を実装

ミドルウェア強化

  • Trailing Slash: alwaysRedirectオプションでワイルドカードルート対応
  • Language: RFC 4647準拠の段階的ロケールコード切り詰め機能

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

claudejamodel: claude-sonnet-4-20250514

v4.12.0

Hono v4.12.0

Hono v4.12.0がリリースされました!このリリースには、Honoクライアントの新機能、ミドルウェアの改善、アダプターの拡張、そしてルーターとコンテキストの大幅なパフォーマンス向上が含まれています。

Honoクライアント用の$path

Honoクライアントに、完全なURLではなくパス文字列を返す$path()メソッドが追加されました。これは、ルーティングやキーベースの操作でパス部分のみが必要な場合に便利です:

const client = hc<typeof app>('http://localhost:8787')

// パス文字列を取得
const path = client.api.posts.$path()
// => '/api/posts'

// パスパラメータ付き
const postPath = client.api.posts[':id'].$path({
  param: { id: '123' },
})
// => '/api/posts/123'

// クエリパラメータ付き
const searchPath = client.api.posts.$path({
  query: { filter: 'test' },
})
// => '/api/posts?filter=test'

URLオブジェクトを返す$url()とは異なり、$path()はプレーンなパス文字列を返すため、ルーターでの使用やキャッシュキーとして便利です。

@ShaMan123 さん、ありがとうございます!

RPCクライアント用のApplyGlobalResponseタイプヘルパー

新しいApplyGlobalResponseタイプヘルパーにより、RPCクライアントのすべてのルートにグローバルエラーレスポンスタイプを追加できます。これは、app.onError()やグローバルミドルウェアからの共通エラーレスポンスをタイピングする際に便利です:

const app = new Hono()
  .get('/api/users', (c) => c.json({ users: ['alice', 'bob'] }, 200))
  .onError((err, c) => c.json({ error: err.message }, 500))

type AppWithErrors = ApplyGlobalResponse<
  typeof app,
  {
    401: { json: { error: string; message: string } }
    500: { json: { error: string; message: string } }
  }
>

const client = hc<AppWithErrors>('http://api.example.com')

// クライアントは成功とエラーの両方のレスポンスを認識
const res = await client.api.users.$get()
// InferResponseTypeには { users: string[] } | { error: string; message: string } が含まれる

@mohankumarelec さん、ありがとうございます!

SSGリダイレクトプラグイン

SSG用の新しいredirectPluginは、HTTPリダイレクトレスポンス(301、302、303、307、308)用の静的HTMLリダイレクトページを生成します:

import { toSSG } from 'hono/ssg'
import { defaultPlugin, redirectPlugin } from 'hono/ssg'

const app = new Hono()
app.get('/old', (c) => c.redirect('/new'))
app.get('/new', (c) => c.html('New Page'))

// redirectPluginはdefaultPluginより前に配置する必要があります
await toSSG(app, fs, {
  plugins: [redirectPlugin(), defaultPlugin()],
})

生成されるリダイレクトページには、<meta http-equiv="refresh">タグ、canonicalリンク、robots noindexメタタグが含まれます。

@3w36zj6 さん、ありがとうございます!

Basic Auth用のonAuthSuccessコールバック

Basic Authミドルウェアに、認証成功後に呼び出されるonAuthSuccessコールバックがサポートされました。これにより、Authorizationヘッダーを再解析することなく、コンテキスト変数の設定やログ記録が可能になります:

app.use('/auth/*', basicAuth({
  username: 'hono',
  password: 'ahotproject',
  onAuthSuccess: (c, username) => {
    c.set('user', { name: username, role: 'admin' })
    console.log(`User ${username} authenticated`)
  },
}))

コールバックは非同期関数やverifyUserモードでも動作します。

@AprilNEA さん、ありがとうございます!

AWS Lambda、Cloudflare Pages、Netlify用のgetConnInfo

getConnInfo()が3つの追加アダプターで利用可能になりました:

// AWS Lambda(API Gateway v1、v2、ALBをサポート)
import { handle, getConnInfo } from 'hono/aws-lambda'

// Cloudflare Pages
import { handle, getConnInfo } from 'hono/cloudflare-pages'

// Netlify
import { handle, getConnInfo } from 'hono/netlify'

app.get('/', (c) => {
  const info = getConnInfo(c)
  return c.text(`Your IP: ${info.remote.address}`)
})

@rokasta12 さん、ありがとうございます!

Trailing Slashミドルウェア用のalwaysRedirectオプション

trailing slashミドルウェアにalwaysRedirectオプションがサポートされました。有効にすると、ミドルウェアはハンドラー実行前にリダイレクトを行い、ワイルドカードルートでtrailing slash処理が動作しない問題を修正します:

app.use(trimTrailingSlash({ alwaysRedirect: true }))
app.get('/my-path/*', async (c) => {
  return c.text('wildcard')
})
// /my-path/something/ は /my-path/something にリダイレクトされ
// ワイルドカードハンドラーが実行される前に処理される

プログレッシブロケールコード切り詰め

languageミドルウェアのnormalizeLanguage関数で、RFC 4647 Lookupベースのプログレッシブ切り詰めがサポートされました。ja-JPのようなロケールコードは、supportedLanguagesにベース言語のみがある場合、jaにマッチします:

app.use('/*', languageDetector({
  supportedLanguages: ['en', 'ja'],
  fallbackLanguage: 'en',
  order: ['cookie', 'header'],
}))
// Accept-Language: ja-JP → 'ja'にマッチ
// Accept-Language: ko-KR → 'en'にフォールバック

@sorafujitani さん、ありがとうございます!

ExecutionContext用のexportsフィールド

ExecutionContextタイプにCloudflare Workers用のexportsプロパティが含まれました。モジュール拡張を使用してWranglerの生成タイプでタイピングできます:

import 'hono'

declare module 'hono' {
  interface ExecutionContext {
    readonly exports: Cloudflare.Exports
  }
}

@toreis-up さん、ありがとうございます!

パフォーマンス改善

TrieRouterが1.5倍〜2.0倍高速化

TrieRouterは、スプレッド構文の使用削減、O(1)のhasChildrenチェック、遅延正規表現生成、冗長プロセスの除去により大幅に最適化されました:

ルートNode.jsDenoBun
short static GET /user1.70x1.40x1.34x
dynamic GET /user/lookup/username/hey1.38x1.69x1.51x
wildcard GET /static/index.html1.51x1.72x1.43x
all together1.58x1.60x1.82x

@EdamAme-x さん、ありがとうございます!

c.json()の高速パス

c.json()c.text()と同じ高速パス最適化が追加されました。カスタムステータス、ヘッダー、または確定状態が存在しない場合、Headersオブジェクトを割り当てることなく直接Responseが作成されます:

// この一般的なパターンが高速化されました
return c.json({ message: 'Hello' })

ベンチマーク結果:

メトリック変更前変更後変化
Reqs/sec92,26895,244+3.2%
Latency5.42ms5.25ms-3.1%
Throughput17.24MB/s19.07MB/s+10.6%

@mgcrea さん、ありがとうございます!

新機能

  • feat(client): RPCクライアント用のApplyGlobalResponseタイプヘルパーを追加 #4556
  • feat(ssg): リダイレクトプラグインを追加 #4599
  • feat(client): $path #4636
  • feat(basic-auth): コンテキストキーとコールバックオプションを追加 #4645
  • feat(adapter): AWS Lambda、Cloudflare Pages、Netlify用のgetConnInfoを追加 #4649
  • feat(trailing-slash): ワイルドカードルートをサポートするalwaysRedirectオプションを追加 #4658
  • feat(language): normalizeLanguageにプログレッシブロケールコード切り詰めを追加 #4717
  • feat(types): ExecutionContextにexportsフィールドを追加 #4719

パフォーマンス

  • perf(context): c.text()最適化に合わせてc.json()に高速パスを追加 #4707
  • perf(trie-router): パフォーマンス改善(1.5倍〜2.0倍) #4724
  • perf(context): 新しいResponseにcreateResponseInstanceを使用 #4733

すべての変更

  • fix(jsx/dom): render children loopで空配列を処理 by @mixelburg in #4729
  • perf(jsx/dom): 繰り返しflatteningを避けるため開始時に一度childrenをflatten by @usualoma in #4730
  • fix(client): フォームデータシリアライゼーションでundefined値をスキップ by @aidenlx in #4732
  • feat(client): RPCクライアント用のApplyGlobalResponseタイプヘルパーを追加 by @mohankumarelec in #4556
  • feat(ssg): リダイレクトプラグインを追加 by @3w36zj6 in #4599
  • feat(client): $path by @ShaMan123 in #4636
  • feat(basic-auth): コンテキストキーとコールバックオプションを追加 by @AprilNEA in #4645
  • feat(adapter): AWS Lambda、Cloudflare Pages、Netlify用のgetConnInfoを追加 by @rokasta12 in #4649
  • feat(trailing-slash): ワイルドカードルートをサポートするalwaysRedirectオプションを追加 by @yusukebe in #4658
  • perf(context): c.text()最適化に合わせてc.json()に高速パスを追加 by @mgcrea in #4707
  • feat(language): normalizeLanguageにプログレッシブロケールコード切り詰めを追加 by @sorafujitani in #4717
  • feat(types): ExecutionContextにexportsフィールドを追加 by @toreis-up in #4719
  • perf(trie-router): パフォーマンス改善(1.5倍〜2.0倍) by @EdamAme-x in #4724
  • perf(context): 新しいResponseにcreateResponseInstanceを使用 by @yusukebe in #4733
  • Next by @yusukebe in #4735

新しいコントリビューター

  • @mixelburg が #4729 で初回コントリビュート
  • @aidenlx が #4732 で初回コントリビュート
  • @mohankumarelec が #4556 で初回コントリビュート
  • @ShaMan123 が #4636 で初回コントリビュート
  • @rokasta12 が #4649 で初回コントリビュート
  • @mgcrea が #4707 で初回コントリビュート

Full Changelog: v4.11.10...v4.12.0