この記事何?
エンジニア歴1年半。業務で利用しているHonoが大好きだが、TSもプログラミング知識も弱々すぎて上手く使いこなせない。速いはずが多分生かせてない。
ちゃんと理解するためにソースコードリーディングしたい。
でも目的なくソースコード眺めても意味ないし……ねむい……
そうだ!PRを全部読めば、変遷やなぜ変更されているかストーリー的に分かるのでは。
と思ったのでチャレンジしてみる。PR2000以上あるので、全部できるかは知らん。
https://github.com/honojs/hono
#106 chore: set up prettier
Prettierの導入
// .prettierrc
{
"printWidth": 100,
"trailingComma": "es5",
"tabWidth": 2,
"semi": false, // セミコロンなし
"singleQuote": true, // シングルクォート
"jsxSingleQuote": true,
"endOfLine": "lf"
}
107 refactor: router must have only one hander
ルーターのリファクタリング
// 変更前:
// 複数のハンドラーを返す
match(method: string, path: string): Result<T>[] | null
// 変更後:
// 1つのハンドラーだけを返す
match(method: string, path: string): Result<T> | null
ルーターは「最初にマッチしたハンドラー」だけを返す
これなんでこうしたんだろう。複数返しても便利そうな気がするが。
#108 Optimize router
ルーターの最適化
// パスパターンの解析結果をキャッシュ
const cache = new Map<string, ParsedPath>()
function parsePath(path: string): ParsedPath {
if (cache.has(path)) {
return cache.get(path)!
}
const parsed = /* 解析処理 */
cache.set(path, parsed)
return parsed
}
#109 feat: Introduce RegExpRouter for fallback
RegExpRouterの導入
- Trieルーター: 高速だが複雑なパターンに弱い
- RegExpRouter: 柔軟だがやや遅い
export class RegExpRouter<T> implements Router<T> {
routes: { method: string; path: string; handler: T }[] = []
add(method: string, path: string, handler: T): void {
this.routes.push({ method, path, handler })
}
match(method: string, path: string): Result<T> | null {
// ルートを順番にチェック
for (const route of this.routes) {
if (route.method !== method) continue
const regex = this.buildRegex(route.path)
const match = path.match(regex)
if (match) {
return {
handler: route.handler,
params: this.extractParams(route.path, match)
}
}
}
return null
}
}
110 feat: app.notFound for setting default 404 not found
c.notFound() の追加
// 変更前:
// 404を自前で返す
app.get('/users/:id', async (c) => {
const user = await findUser(c.req.param('id'))
if (!user) {
return new Response('Not Found', { status: 404 })
}
return c.json(user)
})
// 変更後:
// c.notFound() で簡単に404を返せる
app.get('/users/:id', async (c) => {
const user = await findUser(c.req.param('id'))
if (!user) {
return c.notFound() // シンプルに返せる
}
return c.json(user)
})