Honoのv3.2が出ました
Honoのv3.2が出ました。
今回のアップデートについて、リリースノートとほぼ同じ内容ですが、書きます。
Honoのステータス
ちなみに現在のHonoのステータス。GitHubスターは4.4Kとなっています。
新しい機能
今回はマイナーアップデートとなります。破壊的変更は含まれないものの、大きな機能がいくつか追加されました。
- 2つの新しいルーター: LinearRouter and PatternRouter
- プリセットという概念と実装:
hono/tiny
,hono/quick
app.mount()
- Node adapter serverの初のメジャーバージョン「v1.0.0」がリリース
- AWS Lambda function URLsのサポート
- Cookie Middlewareの追加
-
hono/nextjs
からhono/vercel
へのリネーム
ではひとつずつ見ていきましょう。
新しいルーター
2つの新しいルーターを紹介します。どちらも@usualomaさんが作りました。
LinearRouter
LinearRouterは非常にquickです。Honoが標準で使っているRegExpRouterはJavaScript界で一番速いルーターの一つですが、ルーティングパスを登録するのが少しだけ遅いです。
app.get('/', handler) // <=== パスの登録 - ここが少し遅い
//...
app.fetch(request) // <=== ルーティングする - ここはめちゃ速い
ですので、Fastly Compute@Edgeなど、リクエストごとに毎回アプリが初期化される環境ではRegExpRouterがベストの選択とは言えません。
LinearRouterはルーティングパスの登録を非常に素早く行います。他のJavaScriptの高速なルーターと比べても速いです。以下がパスの登録フェーズを含めたベンチマークの結果の一つです。
• GET /user/lookup/username/hey
----------------------------------------------------- -----------------------------
LinearRouter 1.82 µs/iter (1.7 µs … 2.04 µs) 1.84 µs 2.04 µs 2.04 µs
MedleyRouter 4.44 µs/iter (4.34 µs … 4.54 µs) 4.48 µs 4.54 µs 4.54 µs
FindMyWay 60.36 µs/iter (45.5 µs … 1.9 ms) 59.88 µs 78.13 µs 82.92 µs
KoaTreeRouter 3.81 µs/iter (3.73 µs … 3.87 µs) 3.84 µs 3.87 µs 3.87 µs
TrekRouter 5.84 µs/iter (5.75 µs … 6.04 µs) 5.86 µs 6.04 µs 6.04 µs
summary for GET /user/lookup/username/hey
LinearRouter
2.1x faster than KoaTreeRouter
2.45x faster than MedleyRouter
3.21x faster than TrekRouter
33.24x faster than FindMyWay
また、このコメントによるとFastly Compute@Edgeの環境ではRegExpRouterより40%速くなりました。
PatternRouter
PatternRouterは非常にtinyです。HonoのデフォルトのルーターはSmartRouterで、RegExpRouterとTrieRouterが登録されています。たいていの場合は、高速なRegExpRouterが動き、TrieRouterはRegExpRouterがカバーできないレアケースを補います。とても高性能なのですが、少しファイルサイズが大きくなってしまいます。そこで、ファイルサイズの小さい、PatternRouterの出番です。
もしリソースが限られている場面なら、PatternRouterが使った方がいいでしょう。
PatternRouterだけを使ったHonoアプリケーションのサイズは12KB以下と非常に小さいです。
yusuke $ esbuild --outdir=dist --bundle --minify ./src/index.ts
dist/index.js 11.9kb
⚡ Done in 9ms
ちなみに、Expressは572KBです。
プリセットという概念と実装
Honoにはこのように目的別にいくつかのルーターがあります。ユーザーはHonoのコンストラクタで好きなルーターを指定することができます。
プリセットは、毎回ルーターを指定せずとも一般的なユースケースに対応するものです。どのプリセットを使ってもHono
クラスの使い方は全て同じです。
今回はhono/tiny
とhono/quick
を紹介します。
hono/tiny
hono/tiny
プリセットはPatternRoutrerだけを使います。つまり以下のコードのようなものです。
this.router = new PatternRouter()
hono/tiny
を使うには、hono/tiny
をimport
して、Hono
クラスをいつもと同じように使います。
import { Hono } from 'hono/tiny'
const app = new Hono()
//...
これだけで、ルーターが切り替わり、ファイルサイズが小さくなります。
hono/quick
hono/quick
プリセットはLinearRouterだけを使います。
this.router = new LinearRouter()
他のプリセットを同じようにhono/quick
を使うことができます。
import { Hono } from 'hono/quick'
どのプリセットを使えばいいのか?
これで我々はhono
、hono/tiny
、hono/quick
と3つのプリセットを手に入れました。ではどのプリセットを使えばいいのでしょうか?以下を参考にしてください。
プリセット | 最適なプラットフォーム |
---|---|
hono |
ほとんどのユースケースでオススメです。ルーティング登録がhono/quick より遅いとはいえ、一度登録されれば高いパフォーマンスを発揮します。DenoやBun、それにNode.jsなどを使った常駐型のサーバーには最適です。また、Cloudflare WorkersやDeno Deploy、Lagonでもこのプリセットを使えばいいでしょう。というのもこれらのようなv8 isolateを使った環境では、isolateは起動後しばらく行き続けるからです(時間が決まっていたり、メモリなどの状況に応じて変化したります)。 |
hono/quick |
このプリセットはリクエストのたびにアプリケーションが初期化されるような環境に適しています。Fastly Compute@Edgeはこれに従うので、このプリセットを使うといいでしょう。 |
hono/tiny |
このプリセットは一番ファイルサイズの小さいプリセットです。リソースが限られている環境にはいいでしょう。 |
app.mount()
新しい機能、app.mount()
を使うと、itty-routerなど、Hono以外のフレームワークを使ったアプリケーションと統合することができます。
// Create itty-router application
const ittyRouter = IttyRouter()
// Handle `GET /itty-router/hello`
ittyRouter.get('/hello', () => new Response('Hello from itty-router!'))
// Hono application
const app = new Hono()
// Hono application
app.mount('/itty-router', ittyRouter.handle)
Remixもできます。
import { Hono } from 'hono'
import { env } from 'hono/adapter'
import { serveStatic } from 'hono/cloudflare-workers'
import { createRequestHandler } from '@remix-run/cloudflare'
import * as build from './build'
// Remix application
// @ts-ignore
const handleRemixRequest = createRequestHandler(build, process.env.NODE_ENV)
// Hono application
const app = new Hono()
// Static files for Remix
app.get(
'/remix/build/*',
serveStatic({
root: './',
})
)
// Mount Remix app
app.mount('/remix', handleRemixRequest, (c) => {
return { env: env(c) }
})
これはつまり、itty-router、Remix、Qwik、もしくはSolidJSなど、どんなフレームワークで作ろうともHonoのアプリケーションにマウントすることができるということです。
エコシステム
このapp.mount()
によって、我々は2つのコンセプトを提唱します。adaptとmountです。adaptとはHonoがあらゆるランタイムに「適応する」こと、mountとはあらゆるフレームワークを「マウントする」ことです。これとミドルウェアを組み合わせることで、以下の図のような非常に壮大なエコシステムをつくることができます。
Honoはウェブフレームワークなだけにはとどまらなくなります。
このコンセプトの大きな側面の一つとして、フレームワークは個別にCloudflare Workers、Cloudflare Pages、Vercel、Deno、Bunなどそれぞれのプラットフォーム用のアダプタを用意することが必要なくなります。
Honoがないと以下のようになるでしょう。
もし、あなたのフレームワークがWeb Standard APIに準拠するものであれば、こうした作業は必要なくなります。Honoがあなたのフレームワークをマウントし、どんなランタイムでも動くようにしてあげるのです。
さらに、他のフレームワークでHonoのミドルウェアを使うことができます。例えば、iity-routerで作ったアプリケーションにBasic認証を追加したい時に、個別でスクラッチから実装する必要はなく、Honoのミドルウェアを追加するだけで済みます。
app.use('/another-app/admin/*', basicAuth({ username, password }))
これが私達が作りたかったエコシステムの姿です。
Node.js adapter serverのv1.0.0がリリース
Node.js adapterの最初のメジャーバージョンとなるv1.0.0がさきほどリリースされました!このバージョンではNode.js v18以降のネイティブなWeb Standard APIのみを使っています。外部ライブラリでポリフィルはしていません。これによりファイルサイズがものすごく抑えられました。そして、我々は本当にWeb Standardを追従していくことになりました。
今すぐ使い始めることができます。
npm install @hono/node-server
npmからインストールしたら、serve
をimport
してHonoのアプリに適応するだけです。
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono meets Node.js'))
serve(app, (info) => {
console.log(`Listening on http://localhost:${info.port}`)
})
ホスト名を含んだルーティングのサポート
新しいgetPath()
を使うとホスト名を含んだルーティングを行うことができます。
const app = new Hono({
getPath: (req) => req.url.replace(/^https?:\/\//, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
app.get('www2.example.com/hello', (c) => c.text('hello www2'))
このgetPath()
を応用すると、例えば、host
ヘッダに基づいたルーティングなんてものもできてしまいます。
const app = new Hono({
getPath: (req) => req.headers.get('host') + req.url.replace(/^https?:\/\/[^\/]+/, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
// The following request will match the route:
// new Request('http://www1.example.com/hello', {
// headers: { host: 'www1.example.com' },
// })
AWS Lambda functions URLsのサポート
AWS LambdaアダプターがLambda functions URLsをサポートしました。
Cookieミドルウェア
新しくCookieミドルウェアが導入されます。
import { getCookie, setCookie } from 'hono/cookie'
// ...
app.get('/cookie', (c) => {
const yummyCookie = getCookie(c, 'yummy_cookie')
// ...
setCookie(c, 'delicious_cookie', 'macha')
//
}
これに伴い、c.req.cookie()
とc.cookie()
は非推奨となり、次のメジャーリリース「v4」で廃止されます。
hono/nextjs
to hono/vercel
hono/nextjs
をhono/vercel
にリネームしました。hono/nextjs
は使えますが、非推奨となり、「v4」で廃止されます。
その他
他のアップデートは以下の通りです。
-
serve-static
にrewriteRequestPath
オプションが追加されました。 -
app.routerName
が追加されました。 - レスポンスヘッダの値を完全にクリアできるようになりました。
-
http-status.ts
からHTTPステータスメッセージを削除しました。 - パフォーマンスの向上。
- バグの修正。
まとめ
以上!全てのコントリビューター、スポンサー、ユーザーに感謝です。
Discussion