この記事何?
エンジニア歴1年半。業務で利用しているHonoが大好きだが、TSもプログラミング知識も弱々すぎて上手く使いこなせない。速いはずが多分生かせてない。
ちゃんと理解するためにソースコードリーディングしたい。
でも目的なくソースコード眺めても意味ないし……ねむい……
そうだ!PRを全部読めば、変遷やなぜ変更されているかストーリー的に分かるのでは。
と思ったのでチャレンジしてみる。PR2000以上あるので、全部できるかは知らん。
https://github.com/honojs/hono
#31 Feature/html method
Contextにc.html()メソッドを追加
これにより、HTMLレスポンスを簡潔に返せる
src/context.ts
export class Context {
// 既存: c.text(), c.json()
// 新規追加
html(body: string): Response {
// 型チェック
if (typeof body !== 'string') {
throw new TypeError('html method arg must be a string!')
}
// HTMLレスポンスを返す
return this.newResponse(body, {
status: 200,
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
})
}
}
// 変更前
app.get('/', () => {
const html = renderSSR(<App />)
// 手動でResponseを作成
return new Response(html, {
headers: {
'Content-Type': 'text/html',
},
})
})
// 変更後
app.get('/', (c) => {
const body = renderSSR(<App />)
// c.html() で簡潔に
return c.html(body)
})
フレームワーク作ったことないけど、こういう「あったら嬉しい」「こう書けたら嬉しい」「アレにあるようなメソッドが欲しい」をつけていく作業なのかもしれない。
#32 Refactor
- package-lock.jsonの削除(Yarnを使用しているため)
- READMEの改善
- JSX-SSRサンプルの改善
- Lintの修正
#33 Add worktop benchmark
ベンチマークに worktop を追加。
worktopって何かなと思ったけど、Cloudflare Workers向けの別のフレームワークぽい。
| フレームワーク | 速度(ops/sec) | 順位 |
|---|---|---|
| hono | 748,188 | 1位 |
| sunder | 332,339 | 2位 |
| worktop | 205,906 | 3位(新規) |
| itty-router | 158,817 | 4位 |
おお、READMEの
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, fast and simple...の説明がfast -> ultrafastへ変更になってる。めちゃいい。ワクワク。
#34 status and headers args on context text/json/html method
Context のレスポンスメソッドにオプションでステータスコードとカスタムヘッダーを指定できるように修正
// 変更前:
export class Context {
text(body: string): Response {
return this.newResponse(body, {
status: 200, // 固定
headers: {
'Content-Type': 'text/plain',
},
})
}
json(object: object, replacer?: (string | number)[], space?: string | number): Response {
const body = JSON.stringify(object, replacer, space) // JSON.stringifyの引数
return this.newResponse(body, {
status: 200, // 固定
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
})
}
...
app.get('/', (c) => c.json({ ok: true })) // 常に200
// 変更後:
export class Context {
text(text: string, status: number = 200, headers: { [key: string]: string } = {}): Response {
headers['Content-Type'] = 'text/plain'
return this.newResponse(text, {
status: status,
headers: headers,
})
}
json(object: object, status: number = 200, headers: { [key: string]: string } = {}): Response {
const body = JSON.stringify(object) // シンプルに
headers['Content-Type'] = 'application/json; charset=UTF-8'
return this.newResponse(body, {
status: status,
headers: headers,
})
}
...
app.post('/api/posts', (c) => c.json({ message: 'Created!' }, 201)) // ステータス指定可能
app.get('/api/data', (c) => c.json({ data: 'value' }, 200, { 'X-Custom': 'Header' })) // ヘッダー追加可能
- デフォルト引数で後方互換性を維持
#35 Refactor
- params の戻り値の型を any から string に変更
- 型をエクスポート
- JSX-SSRサンプルの改善
など
Contextが何者かいつもイメージしづらかったけど、PR順番に追っていくと優しさの塊だった。ありがてぇ