この記事何?
エンジニア歴1年半。業務で利用しているHonoが大好きだが、TSもプログラミング知識も弱々すぎて上手く使いこなせない。速いはずが多分生かせてない。
ちゃんと理解するためにソースコードリーディングしたい。
でも目的なくソースコード眺めても意味ないし……ねむい……
そうだ!PRを全部読めば、変遷やなぜ変更されているかストーリー的に分かるのでは。
と思ったのでチャレンジしてみる。PR2000以上あるので、全部できるかは知らん。
https://github.com/honojs/hono
#16 Can use async on handler
ハンドラーでasync/awaitが使えるように
変更前:
// 同期処理のみ
app.get('/hello', () => {
return new Response('Hello')
})
// fetch などの非同期処理が使えない
app.get('/data', () => {
const data = fetch('https://api.example.com/data') // Promiseが返る
return new Response(data) // [object Promise] になってしまう
})
変更後:
// async/await が使える
app.get('/data', async () => {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
return new Response(JSON.stringify(data))
})
ミドルウェアが完全にasync/awaitベースに
変更前:
// 同期的なミドルウェア
const logger = (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`)
next() // ← 同期呼び出し
}
const addHeader = (c, next) => {
next() // ← 先に次のハンドラーを呼ぶ
c.res.headers.add('x-message', 'This is middleware!')
}
変更後:
// 非同期ミドルウェア
const logger = async (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`)
await next() // ← 非同期呼び出し(必ずawait!)
}
const addHeader = async (c, next) => {
await next() // ← 次のハンドラーを待つ
await c.res.headers.add('x-message', 'This is middleware!')
}
#17 Logger middleware
Loggerミドルウェアの追加。
新規ファイル: src/middleware/logger.js
const logger = (fn = console.log) => {
return async (c, next) => {
const { method } = c.req
const path = getPathFromURL(c.req.url)
log(fn, LogPrefix.Incoming, method, path)
const start = Date.now()
try {
await next()
} catch (e) {
log(fn, LogPrefix.Error, method, path, c.res.status || 500, time(start))
throw e
}
log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start))
}
}
使い方:
const { Hono, Middleware } = require('hono')
const app = new Hono()
// Logger ミドルウェアをマウント
app.use('*', Middleware.logger())
app.get('/', () => new Response('Hello'))
出力例:
--> GET /
<-- GET / 200 5ms
const LogPrefix = {
Outgoing: '-->',
Incoming: '<--',
Error: 'xxx',
}
const colorStatus = (status) => {
const out = {
7: `\x1b[35m${status}\x1b[0m`, // 700番台: マゼンタ(未使用)
5: `\x1b[31m${status}\x1b[0m`, // 500番台: 赤(サーバーエラー)
4: `\x1b[33m${status}\x1b[0m`, // 400番台: 黄(クライアントエラー)
3: `\x1b[36m${status}\x1b[0m`, // 300番台: シアン(リダイレクト)
2: `\x1b[32m${status}\x1b[0m`, // 200番台: 緑(成功)
1: `\x1b[32m${status}\x1b[0m`, // 100番台: 緑(情報)
0: `\x1b[33m${status}\x1b[0m`, // その他: 黄
}
return out[(status / 100) | 0]
}
ログの種類(入力、出力、ステータスコードの色付け)もこうやってセッティングしているのか〜。ほえ〜。
#18 In test, use edge-mock instead of node-fetch
テストで使う依存関係をnode-fetchからedge-mockに変更
#19 Use test directory
ディレクトリ整理
https://github.com/honojs/hono/pull/19
#20
なし
PRがすごい綺麗だ〜。変更が10ファイル程度に収まっている。OSSとして育てていくの視野に入れてるとしても、個人開発でこれだけ綺麗にPR作っていくのすごい。見習いたい。