Honoのコミット記録
What is this?
ただのHonoにコミットされたものを記録していくためのメモ
凄い・・・笑
4.3.7以降の変更
内部的な型のリファクタリング
型関係のリファクタリングのようです。特に表立ってのインターフェースが変更されたわけではありません。
Set Cookieが正常生成されない不具合修正
import { setCookie } from "hono/cookie";
const app = new Hono();
app.get("/does-not-work", (c) => {
setCookie(c, "hello", "world");
setCookie(c, "hello", "world2");
const res = new Response("does not work");
return c.body(res.body, res); // <-- this
});
上記のサンプルコード c.body(res.body, res)
のようにレスポンスオブジェクトの初期値を渡してレスポンスを生成する場合にレスポンスヘッダーの Set-Cookie
が正常に返却されないという不具合の修正です。
forwardRef
を使用したコンポーネントで ref
を必ず渡す必要がある不具合修正
hono/jsxの
import { forwardRef } from 'hono/jsx'
const DivComponent = forwardRef((props, ref) => {
return <div {...props} ref={ref} />
})
function Render() {
return <DivComponent /> // <-- type error(ref not specified)
}
上記のサンプルコードのように forwardRef
を使用すると ref
のpropsを渡す必要があるという型になっているが、optionalでも問題ないように型の修正が行われています。
上記の変更で 4.3.8
がリリースされています
4.3.8以降の変更
CreateHandlersInterface
の型定義をexportするように変更
import type { CreateHandlersInterface } from 'hono/factory'
上記のコードで factory.createHandlers
の生成する型を使えるようになったようです。
ALBのマルチバリューヘッダー設定に対応
同キーのクエリパラメータ(http://www.example.com?&myKey=val1&myKey=val2
など)がある場合に multiValueQueryStringParameters
としてAWS Lambdaに送信します。それの対応が行われました。
上記の変更で 4.3.9 がリリースされています
4.3.9以降の変更
Secure Headers Middleware の Node.js依存の解消
Secure Headers Middlewareは nonce
属性に設定する際のbase64値をNode.jsのAPIに依存していましたが、Node.jsに依存しない変更が行われました。この変更でCloudflare WorkersでSecure Headers Middlewareを使用する場合は nodejs_compat
の compatibility_flags
の設定が必要でしたが、不要になります。
4.3.9以降の変更 その2
Status Codeが指定のコードで返らない場合がある不具合の修正
ちょっと特殊ですが HTTPException
を使用した例外をスローした際のStatus Codeが返らず、例外となった元のResponseオブジェクトのStatus Codeで返ってしまうという不具合の修正です。具体的には以下のコード例で400が返らず、200が返ってしまうということの修正が行われました。
app.get("/example-a", (c) => {
throw new HTTPException(400, {
res: new Response("An exception", { status: 200 }),
});
});
304を返す場合のヘッダー設定をHonoから提供
304を返す場合に設定するヘッダー設定(ETag)をHonoからPublicな設定として提供されるようになりました。これにより304のヘッダーを設定するのが用意になります。
import { etag, RETAINED_304_HEADERS } from 'hono/etag'
app.use(
'/etag/*',
etag({
retainedHeaders: ['x-message-retain', ...RETAINED_304_HEADERS],
})
)
上記の変更で 4.3.10 がリリースされています
4.3.10以降の変更
secret
に設定漏れがあった場合に正しいエラーメッセージを表示するように修正
JWT Auth Middlewareの
JWT Auth Middlewareを使用する場合に secret
を設定が必要ですが、secret
が undefined
など定義されていない場合はJWTの検証エラーとなりエラー理由がわかりにくいため、secret
が設定されていない場合にはその旨のエラーを表示するように修正されました。
上記の変更で 4.3.11 がリリースされています
4.3.11以降の変更
JWT Auth Middlewareの secret に設定漏れがあった場合に正しいエラーメッセージを正しいメッセージに修正
メッセージに "secret
ではなく "secret"
とダブルクォーテーションが抜けていたメッセージの修正です。
4.3.11以降の変更 その2
4.4.0の内容がマージされてるので昨日の内容とコミット順が前後します。
JSDoc によるドキュメントの追加
JSDoc によるドキュメントが大量に追加されています。コミットを1つ1つ書くと多くなってしまうので纏めます。
JSRのサポート
4.4.0からJSRがサポートされました。JSRからHonoがインストールできるようになっています。
req.paramsの型を見やすい型に変更
今までRequest Handlerの引数から取得する req.params
で複数のURLパラメータがある場合は
type params {
version: string
} & {
id: string
}
となっていましたが、これが1つに纏まって
type params {
version: string
id: string
}
と表示されるようになるリファクタリングです。
convertFormDataToBodyData
のリファクタリング
内部関数である
この convertFormDataToBodyData
の役割を詳しく追ってないのでなんのための関数かわかりませんが、内部的なこの関数の FormData
生成のために2重で生成されていたが FormData
を1つの変数で生成できるようにリファクタリングが行われています。
上記の変更で 4.4.0-rc.1 がリリースされています
この4.4.0の正式版へのコミットがされていますが、多いのでまた後日。
4.4.0-rc.1以降の修正
4.4.0まで別ブランチで開発してたものが多く数が多いので特に重要ではないものは軽くしか触れません。
READMEへJSRバッジの修正
DenoからJSRにバッジの表示を変更しています。
JSRへPublishするためのCIのトリガーの修正
tagがPushされたら実行するように変更
Deno環境でのベンチマークプログラムの import パスの変更
Denoで実行しているベンチマークプログラムはsloppy importsという機能を使ってimportを解釈されるパスに変更されました。
HonoのESLintルール変更
@hono/eslint-config
が 0.0.6
にUpdateされ、そのルールに沿ったコードに修正されています。
JWT Auth Middlewareの型定義のexportを追加
JWT Auth Middlewareの JwtVariables
SecureHeadersVariables
TimingVariables
の型がexportされて使用できるようになりました。
JSDocの追加
module系のドキュメントの追加です。
Honoで使用されるReactのバージョンの取得が可能になるように修正
Honoに依存したReactのライブラリを作成する場合にReactのバージョンにより処理を分岐できるようにHonoが使用するReactのバージョンを取得できるようにする修正がされました。
CODE_OF_CONDUCT.md
などのリンク追加
READMEに
各種ドキュメントのリンクがREADMEに追加されました。
上記の変更で 4.4.0 がリリースされています
この4.4.0のリリース以降もコミットがされていますが、多いのでまた後日。
細かいですが、
途中のparamsをparasにtypoしてますね…
ありがとうございます!修正しました。
4.4.0以降の修正
pretty
が存在するかどうかの条件式から不要な条件式を削除
Pretty JSON Middlewareの クエリパラメータに
全体のコードとは若干異なりますが、上記のような三項演算子の条件までは不要なため削除されました。
- c.req.query('pretty') === '' ? true : false
+ c.req.query('pretty') === ''
multiValueQueryStringParameters
より queryStringParameters
が優先されてしまう不具合の修正
ALBのマルチバリューヘッダー設定の対応で
ALBのマルチヘッダー設定の対応がされましたが、 multiValueQueryStringParameters
と queryStringParameters
の両方が送信される時に queryStringParameters
を優先してパラメータを取得してしまい、パラメータが送信されてくるパラメータが欠損してしまうという不具合が修正されました。
if (event.multiValueQueryStringParameters) {
...
} else {
...
}
となっているので multiValueQueryStringParameters
がある場合はそちらを優先して取得するという変更です。
Object.hasOwn()
を使用するリファクタリング
Objectに指定したプロパティが存在するかどうかの判定に
HonoのAWS LambdaアダプターでALBのProxy判定に Object.hasOwnProperty()
が使用されていましが、 Object.hasOwn()
を使用するようにリファクタリングが行われました。
Object.hasOwn()
はドキュメントにある通り Object.hasOwnProperty()
の代わりに使用できるように設計されおり、 Object.hasOwn()
の使用を推奨されています。また、HonoはNode.js環境ではversion 16以上が動作保証環境になっており、Node.jsでも Object.hasOwn()
が使用できるので問題ないそうです。
hono/client
で FormDataに配列を設定できるように修正
HonoでRPC機能 を使って hono/client
からサーバに送信するする際のFormDataに同一キーのデータつまり配列を送信できるように修正されました。
const res = await client.posts.$post({
form: {
title: 'Hello',
body: 'Hono is a cool project',
list: ['listA', 'listB'] // <-- It has never been sent correctly
},
})
これが可能になっています。
../../
)が正常に生成されない不具合修正
SSGを行う際のパス生成で2階層以上の親のパス(
SSGを行う際は内部的に joinPaths
という関数を呼びますが、この関数を以下のように呼び出すと正常にファイルパスが生成されない不具合が修正されました。
ただし、これは saveContentToFile
という experimentalなAPI に影響する不具合の修正です。
import { saveContentToFile } from 'hono/ssg'
await saveContentToFile({
data: new Promise((resolve) => resolve({ routePath: '..', content: 'test', mimeType: 'text/plain'})),
fsModule: fs,
outDir: '..',
})
一旦28日分までを纏めて記載。29日分は後で追記する予定。
4.4.0以降の修正 その2
ちょっと量が多いのはmainブランチの最新に追いつくためです。
Pull Request templateにドキュメント追加確認のチェックボックスを追加
4.4.0でJSDocによるドキュメントの追加がされましたが、以降はドキュメントをメンテナンスしていく上で修正や追加、削除などがある場合にドキュメントを合わせて修正する必要があるということになりそうです。
request
する場合に duplex
が設定されずにエラーになる場合がある不具合の修正
Honoに定義しているRoutingに
Body Limit Middlewareを使用していてかつ、@hono/node-server
を使用していない場合に以下のようなコードで内部ルーティングを呼び出すとエラーになります。
import {Hono} from 'hono'
import {bodyLimit} from 'hono/body-limit'
const app = new Hono()
app.use(bodyLimit({maxSize: 100 * 1024})) // 100kb
app.post('/hello', async (context) => {
return context.json({message: 'Hello, World!'})
})
const response = await app.request('/hello', { // <-- This is where the error occurs
method: 'POST',
body: JSON.stringify({foo: 'bar'}),
})
これは内部ルーティングではReadable StreamをBodyに設定して送信しますが、Readable Streamを送信する場合は duplex
を設定する必要がありますが、設定されていないことでエラーになるそうです。
@hono/node-server
を使用する場合にエラーにならないのは @hono/node-server
の内部にてReadable Streamを送信する場合に duplex
を付与するロジックが含まれているためです。
onOpen
など呼び出す際にオプショナルチェーンを使って呼び出すようにするリファクタリング
WebSocketのEvent型から
今までは events.onOpen && events.onOpen(evt, wsContext))
のようにEvent型の変数に onOpen
の存在確認を行ってから呼び出していたが、それをオプショナルチェーンを使うようにリファクタリングされました。
- events.onOpen && events.onOpen(evt, wsContext))
+ events.onOpen?.(evt, wsContext))
Context
に server
を渡せるように修正
BunのWebSocket Helperを使用する場合に BunでWebSocketを使用する場合は、下記のコードでいう req
からServerオブジェクトを取り出していたが、Context
に server
を渡せるようになり、指定できるようになる変更がされました。
(ちょっとこれは説明があってるか自信がないです)
import { createBunWebSocket } from 'hono/bun'
const { websocket } = createBunWebSocket()
Bun.serve({
fetch(req, server) {
return app.fetch(req, { ip: server.requestIP(req), server }) <-- `server` can be passed
},
websocket,
})
ドキュメント系のファイルが変更されてもCIでテストが動かないように修正
paths-ignore
を設定して特定ファイルの変更はCIが動作しないように修正されています。
CIのテスト環境にNode.jsの22が対象に追加
Node.jsの22は10月からLTSに入るので先んじてテスト環境に追加されました。
src/*
のTSDocの追加
src/compose.ts
や src/context.ts
の src/
直下のファイルにTSDocが追加されました。
hono/testing
の testClient
で型エラーを起こす不具合の修正
hono/testing
の testClient
で basePath
を使用した以下ようなテストを書くと型エラーが発生する型修正が行われました。
import { Hono } from 'hono';
import { testClient } from 'hono/testing';
const app = new Hono().basePath('/mybasepath');
const route = app.get('/items', async c => c.json({ id: 2 }));
type AppType = typeof route;
const api = testClient<AppType>(app); // <-- If app is specified as an argument here, a type error will occur.
v4向けのブランチをCIの対象外とする修正
v4はすでにリリースされているため不要なため削除されました。
navigator.userAgent
を使用するように修正
一部のランタイム判定に
Deno, Bun, Cloudflare Workers, Nodeは navigator.userAgent
から取得した値でどの環境下なのかを判定するように修正されました。
これらの4環境は navigator.userAgent
をWinterCGで策定された要件通りに実装しているようです。
JSXのスタイルに数値を渡すと正しく反映されない不具合修正
以下ような数値のスタイルを渡すとスタイルに px
が付与されてしまい正しくスタイルとして認識されない不具合が修正されました。
<div style={{ "--hue": 10, "--text": '#000' }}>test</div>
{/* output: <div style="--hue: 10px; --text: #000"> */}
setHeadersToResult
が未使用なので削除される
以前ALB対応で追加された
ALBの対応で追加されたものが未使用のコードがあったため削除されました。
Content-Type
をサポート
JSON APIの
JSON APIの仕様で Content-Type
に application/vnd.api+json
のようなドットを含んだ文字列が入ることがありますが、今までドットを受け入れてなかったので HTTPException
が発生していましたが、それを発生しないようにする修正がされました。
hono/testing
の testClient
の型を修正
testClient
内で any
が使用されていますが、その一部を使用しないで済むようにリファクタリングが行われました。
以上が29日までにmainブランチに行われたコミットです。
4.4.0以降の修正 その3
CONTRIBUTING.md
のコードブロックのシンタックスハイライトの形式を変更
マークダウンのコードブロックのシンタックスハイライトの言語指定が txt
になっていましたが、コマンドなので bash
に変更されました。
重複する型定義の修正
手前味噌ですいません。先日の src/
直下にTSDocが追加されたコミットのdiffを見たら気づいたのですが、同一の型定義が作成されてしまっていたので1つ削除されました。
以上が30日までにmainブランチに行われたコミットです。
後日 上記の変更で 4.4.1 がリリースされています
4.4.1以降の修正
戻り値の型指定を行うようにリファクタリングを実施
どうやら4.4.1のリリースを行ったが、JSRのリリースが正常に行えていなかったようです。その原因がこの戻り値の型指定がなかったためとあります。JSRのリリースに戻り値の型指定が必要ということでしょうか?私もJSRにはまだリリースしてないのでなんとも言えないのですが、そういう風なコミットのようです。
- function test() { console.log('test') }
+ function test(): void { console.log('test') }
上記の変更で 4.4.1 改め 4.4.2 がリリースされています
4.4.2以降の修正
release
に変更
リリースするためのワークフロー名を
GitHub Actionsでリリースを行っていますが、リリースするためのワークフロー名が ci
だったので release
という名称に変更されました。
letによる変数宣言を無くすリファクタリング
意図があってるか不明ですが、 let
で宣言されていた変数を const
で定義するためのリファクタリングが実施されました。
ただ、コードを見るに try {} catch {}
の try
内の最後に return
つまり返り値はあるのですが、 catch
で例外を潰しつつ、返り値がないのはどういうことを意味するのかちょっとわからなかったです。
4.4.2以降の修正 その2
リリースCIのJSRへのpublishジョブ名の変更
JSRに対応したため、ジョブ名もdenoからJSRに変更されました。
いくつかモジュールについてJSDocの追加
JSDocでのドキュメント管理にするために更にいくつかのモジュールについてドキュメントが追加されました。
CodeCovによるカバレッジレポートの追加
CIで各ランタイムのテストなどが実行された後にテストのカバレッジが計測されるようになりました。
JSRに移行した旨の記載がREADMEに追加
4.4.0以降はJSRにHonoがリリースされるので以前の deno.land/x
にはリリースされない旨と deno.land/x
から JSR
への移行方法が追記されました。
また、4.3.11から4.4.0へは特にbraking changeが発生していない旨も合わせて追記されています。(このスクラップを読んでる人にはくどい説明かもしれません)
4.4.2以降の修正 その3
カバレッジバッジをREADMEに追加
先日カバレッジレポートの対応が行われましたが、カバレッジのパーセンテージがREADMEに表示される対応がされました。
DenoのWebSocketのonOpenイベントがトリガーされない不具合を修正
DenoでWebSocketへの接続を行う upgradeWebSocket
内で遅延処理つまりPromise処理があると onOpen
のイベントがトリガーされないという不具合が修正されました。
const app = new Hono()
app.get(
'/ws',
upgradeWebSocket(async (c) => {
await new Promise(resolve => setTimeout(resolve, 5e2)) // Simulate time-consuming operation
return {
onOpen: () => console.log('opened') // can't be trigger
}
})
)
Pull Requestにあったサンプルのままですが、上記のようにPromiseがあると動作しないという不具合が修正されています。原因としてはEventの生成処理前に upgradeWebSocket
を呼んでること原因のようです。
Cloudflare WorkersでWebSocketの接続を行う場合にhttp statusに101が返らない不具合の修正
Cloudflare WorkersでWebSocketを接続する場合にはhttp statusが101が返っていないため接続できない不具合が修正されました。
wrangler
というランタイム名称を workerd
という名称に変更
CIでの
細かい話ですが wranlger
はあくまでCLIであり、Cloudflare Workersのランタイムは workerd
ということでランタイム名が正しい名称に変更されました。
ランタイム名の変更に伴いテストなどのファイル名の配置ディレクトリ名やテストの describe
なども同じく修正されています。
workerd
環境下でのWebSocketのテスト追加
その名の通りCloudflare Workers環境下でのWebSocketのテストが追加されました。
今まではWebSocketの接続ルーティングをもったHonoアプリケーションに対して、WebSocketではないルーティングへのアクセスのみがテストとして定義されていましたが、WebSocketの接続ルーティングへ接続を行い open
message
close
と一通りのイベントが動作するかのテストが追加されました。
またこのコミットにもコメントにもありますが、 workerd
環境下の unstable_dev
を使ってWebSocketの接続を行うには ws
のパッケージが必要になるようです。
AWS Lambda adapterの型定義ファイルを1つに纏めるリファクタリング
AWS Lambdaのadapterには2つのカスタムの型ファイルが存在していました。2つ存在するとそれぞれの使用用途が明確でなく、型ファイルの追加を行う場合にどちらに追加するか迷うことが発生するため1つに纏められました。
カバレッジから型定義のみのファイルは除外するように修正
カバレッジを計測しますが、型定義のみのファイルはカバレッジの対象に含める必要はないので、その修正が行われました。
4.4.2以降の修正 その4
hono/quick
と hono/tiny
のテスト追加
hono/quick
もしくは hono/tiny
のテストかどうかというのは表現的に怪しいですが、Honoはv4で getRouterName
というヘルパーが追加されましたが、hono/quick
か hono/tiny
で作成されたHono
インスタンスに対して getRouterName
で名称が取得できるかどうかというテストが追加されています。
非公式のhttp statusの型名のタイプミスを修正
http statusには200や404といった公式なステータスと218や520といった非公式なステータスが存在します。
Honoでhttp statusを指定する場合に非公式なステータスを使用する場合は今まで UnOfficalStatusCode
と型名がつけられていましたが、正しくは UnofficialStatusCode
(3文字目のオーが小文字) という名称に変更されました。ただ、今すぐ以前の UnOfficalStatusCode
の型名が使用できるのではなく deprecated ですが使用することは可能です。
app.mount
時にアクセスのあったルーティングパスのRequestオブジェクトを指定できるように修正
Honoには mount
という機能が存在します。 mount
はHonoやHono以外のルーティングをHonoのルーティングで上書きするというような機能です。
import { Router as IttyRouter } from 'itty-router'
import { Hono } from 'hono'
// Create itty-router application
const ittyRouter = IttyRouter()
// GET /itty-router/hello
ittyRouter.get('/hello', (request) => new Response(request.url))
const app = new Hono()
app.mount('/itty-router', ittyRouter.handle)
この例では IttyRouter
では /hello
を定義していますが、それをHonoがマウントして /itty-router/hello
で元の IttyRouter
のルーティングにアクセスできるようにするというものです。
しかし、この例で書いてるように IttyRouter
側では本来 /hello
で受けているので本来であればレスポンスの中の request.url
は /hello
のはずですが、HonoがマウントしているためHono側で受けたRequestつまり /itty-router/hello
となります。もちろんこれはそもそも受けているRequestがそうなので間違いではないですが、 IttyRouter
側からすればマウントする親がどうなっているかというのは考える必要はない場合もあります(リクエストパスで何か処理をしたいのであれば自分が定義したパスだけで考えたい場合など)。
そこで、本来の /hello
のルーティングアクセスのRequestオブジェクトを渡せるように mount
の受け入れれる引数に新たな指定方法が増えました。
import { Router as IttyRouter } from 'itty-router'
import { Hono } from 'hono'
// Create itty-router application
const ittyRouter = IttyRouter()
// GET /itty-router/hello
ittyRouter.get('/hello', (request) => new Response(request.url))
const app = new Hono()
app.mount(
'/itty-router',
ittyRouter.fetch,
{
replaceRequest: (req) => req
}
)
replaceRequest
オプションを渡すことでHonoで受けたRequestではなく、IttyRouter
側 /hello
のRequestをそのまま渡せるようになりました。 replaceRequest
だけでなく optionHandler
というものも渡せて、これは従来の ittyRouter.handle
と同等のハンドラーも指定できるようになっています。
上記の変更で 4.4.3 がリリースされています
4.4.3以降の修正
src/request.test.ts
内のテスト内容のTypoを修正
テスト内容のTypoが修正されました。
HTTPException
クラスを使用しないように修正
Honoのエラーハンドリングで受け取る引数で
HTTPException
というものが、Honoのエラーハンドリングに渡された場合は HTTPException
からエラーのResponseを取得してクライアントに返す処理というものがあります。
しかし、この HTTPException
の独自クラスかどうかという判定のためにimportされており、HTTPException
をimportすることで常に HTTPException
分のファイルサイズ (260B) がバンドルサイズに含まれることを懸念して、importせずに同等のことができるようにという修正がされました。(涙ぐましいがこういう努力が嬉しいですね)
requestハンドラー内でResponseオブジェクトを返さず終了した場合のエラーメッセージをわかりやすメッセージに修正
ニュアンスとしては「たぶんResponseオブジェクトのreturnを忘れてるよ」から「Responseオブジェクトのreturnを忘れない?」って感じのエラーメッセージに修正されています。
.gitpod.yml
を追加
Honoの開発環境をGitpodで使用できるように
GitpodというCodespacesみたいなもの?で開発環境が即座に作成できるように .gitpod.yml
が追加されました。
4.4.3以降の修正 その2
getConnInfo
がexportされていない不具合修正
Honoには ConnInfo Helper というリクエスト元の情報を取得できるヘルパーがあります。ドキュメントの記載どおりに hono/cloudflare-workers
からimportするとエラーになるという不具合が修正されました。
4.4.3以降の修正 その3
ミドルウェアを使用しないハンドラーで Response を返さない場合は404 Responseを返すように修正
ミドルウェアを使用しないしないルーティングで非同期のハンドラーでResponseを返さないと404なるという動きがあるようですが、同期のハンドラーの場合はレスポンスが返されずエラーになっていました。
そこで同期のハンドラーでもResponseを返さないと404 Responseを返すという修正がされました。
const app = new Hono()
app.get('/async', async () => {
return // <-- 404 Response
})
app.get('/sync', () => {
return // <-- error
})
同一型定義の削除
Hono内部のユーティリティの型に Prettify
と Simplify
という同じ型定義ありましたが、同一なので Prettify
が削除されました。
never
になる不具合修正
配列を返すJSONをRPCのインターフェースとして使用すると型が
JSONはオブジェクト( { "foo": "bar" }
)から始まる形式と配列( [{ "foo": "bar" }]
)から始まる形式の両方が可能ですが、配列から始まる形式をJSONとして返すハンドラーをRPCの型として読み込むとハンドラーの返り値の型が配列の型ではなく never
になる不具合が修正されました。
import { Hono } from "hono";
// server
const app = new Hono()
.get(
'/test',
async c => {
return c.json([{ foo: 'bar' }])
}
)
export type APP = typeof app
// client
import { hc } from "hono/client";
const client = hc<APP>('http://localhost')
const resp = await client.test.$get()
const result = await resp.json() <-- type of result becomes `never`
HonoのRPCにリダイレクトによる型のサポートを追加
HonoのRPCに使用するハンドラーの中でリダイレクトを行う分岐などがあると型情報が正常に取得できない問題がありました。この修正でハンドラー内でリダイレクトを行った場合でも型情報が取得されるようになりました。リダイレクトがされる場合を考慮してクライアント側は記述する必要があるということです。
const routes = app.get('/profile', (c) => {
if (!flag) {
return c.redirect('/')
}
return c.json({ name: 'abc' }, 200)
})
const client = hc<typeof routes>('/')
const res = await client.profile.$get()
if (res.status === 302) {
console.log(res.headers.get('Location'))
} else {
const data = await res.json()
// ^ { name: string }
}
for
属性のサポートが追加
hono/jsxで
label
タグなどでよく用いられる for
属性が新たに使用できるようになりました。ただし、for
をそのまま指定するのではなく、Reactと同様に htmlFor
として属性を指定すると for
として出力されるようです。
アンダーバーやハイフンを含む拡張子のファイルを静的ファイルとして配信できない不具合の修正
そのままなのですが、ファイル拡張子にアンダーバーやハイフンを含むファイルが404になってしまう不具合が修正されました。
RPC内部で型のために内部で使用するプロパティ名と同名のプロパティを持つオブジェクトが返却できるように修正
HonoのRPCでは型情報のためのプロパティ(data
, status
, format
)が存在しますが、それと同名のプロパティを持つオブジェクトをハンドラーで返してしまうとRPCの型情報が正しくなるということがありました。そこでHonoのためのプロパティについてはアンダーバーから始まる名称に変更されました。
never
になる不具合修正(の追加修正)
配列を返すJSONをRPCのインターフェースとして使用すると型が
先ほど配列を返すハンドラーをRPCとして使用すると型が never
になる不具合の修正を記載しましたが、それの追加修正です。
発生条件を詳しく見ていないですが、配列にネストした配列を入れると never
になる不具合が追加で修正されました。
静的ファイル配信で404の場合にファイル検索が2回動かなくていいように修正
静的ファイル配信を行う処理で404の場合に配信ファイルの検索が2回動いていた処理ロジックが1回で済むようにリファクタリングされました。
カバレッジのレポート出力にテキストファイルとHTMLファイルの出力を追加
カバレッジレポートの出力は今まではJSONだけでしたが、ローカルなどでの確認が行いやすいようにテキストとHTMLファイルの出力も追加されました。
ConnInfo Helper の型定義ファイルの配置場所を変更
今までは src/helper/conninfo/index.ts
に直接定義されていましたが、型定義は src/helper/conninfo/types.ts
に移して export する形にリファクタリングされました。
上記の変更で 4.4.4 がリリースされています
4.4.4以降の修正
カスタムのVery Headerを設定できるように修正
今まではVery Headerは無条件で Origin
が設定されていましたが、カスタムの値を設定できるようになりました。PRでも書かれていますが、CloudflareのPolishを使用する際にこの変更が必要な場合あるための修正です。
typed-htmx
による型定義が行えない不具合の修正
HonoでhtmxとTypeScriptを使用する際のライブラリの
Honoとhtmxを組み合わせて使用する際に typed-htmx
というライブラリを使用することでJSXの属性に型定義を行えるようになるらしいです。
これが4.4.0のリリースから動作しない不具合が修正されました。原因としてはJSRの対応でGlobalを使用しての定義を削除したことで動作しなくなったらしいです。JSRの対応でGlobalは使用できないので、新しくJSXという名前空間で定義してそれを使用することになったようです。
app.route
の第二引数を必須化
4.0以前は任意の引数だったのですが、4.0以降は指定しないことは非推奨とされていました。そこで今回、その非推奨だった第二引数を必須化する変更です。
(ただ、v4のリリースノートやマイグレーションのドキュメント見ても非推奨になりますという記述が見つけられなかった)
app.on
の第一引数の必須チェックを削除するリファクタリング
これだけ見るとなぜこの行がそもそも存在していたのか不明ですが、元々第一引数は文字もしくは文字の配列が型として定義されていますが、それが無い( if (!method)
)場合は自身を返すという無駄なチェックは必要ないということでチェック処理が削除されました。
4.4.4以降の修正 その2
Context
内のプライベート変数の不要な初期化を削除
Context
内に持つプライベートな変数( _var
)が {}
で初期化されていましたが、そもそも初期化が不要なので undefined
を許容するという変更がされました。 _var
は Variables
を保持する内部変数ですが、値の格納や取得時に _var
自体が存在しているかのチェックがあるために不要という判断をしたようです。
また、このコミットで Context
のカバレッジをあげるためにテストも追加されています。
Honoのベース処理保持ファイルのカバレッジを100%にするためにテストを追加
Honoの基本機能( ErrorHandler
や MiddlewareHandler
など )を保持している src/hono.ts
とそれに付随する src/hono-base.ts
のカバレッジを100%にするためにテストが追加されました。
ResponseのJSONまたはテキストの型をジェネリックで指定する場合にステータスコードの型は省略できるように型を修正
HonoではJSONもしくはテキストを返す場合に c.json
や c.text
といったRequestHeaderの Context
の引数からレスポンスを生成できますが、これをジェネリックで指定することも可能です。しかし、ジェネリックで指定する場合は返すJSONやテキストの型とステータスコードを指定する必要がありました。c.json
などはそもそもステータスコードを指定せずともデフォルトのステータスコードでResponseが生成されるのでこれをジェネリックでも可能とする型修正が行われました。
app.get('/', (c) => {
return c.json<Array<{sample: string}>>([{ sample: 'test1' }, { sample: 'test2' }]) // <-- You do not need to specify the second StatusCode in the json generic type specification.
})
リクエストのBodyをparseする内部処理の中で条件にマッチしないチェック処理を削除するリファクタリングを実施
Hono内部でRequestのBodyをparseする parseBody
という処理の中に存在する特定の if
文は必ずマッチしないため不要な条件チェック処理ということで削除するリファクタリングが実施されました。
リファクタリングを行っただけなので、特に振る舞いなどが変わることはありません。
4.4.4以降の修正 その3
JSXに指定された属性をHTMLタグの属性に変換する処理をリファクタリングし、コードサイズを小さくする修正を実施
HonoのJSXはReactと同様に className
や htmlFor
といった通常の属性とは異なる属性を指定することで通常の class
や for
属性に変換する処理があります。このリファクタリングではJSXの属性をまずはHTMLタグの属性としてすべて扱ってから、JSX独自の属性をHTMLタグ属性に変換したものを足した後にJSXで指定された独自の属性を消すという処理になっていましたが、そもそもJSXの属性からHTMLタグ属性に変換する際にJSXの属性をそのまま追加するか、変換してから追加するかという単に属性を追加していくロジックにリファクタリングされました。
このリファクタリングによりバンドルサイズ(minifyあり)ベースで77bほどサイズが小さくなるようです。
上記の変更で 4.4.5 がリリースされています
4.4.5以降の修正
AWS Lambdaの環境でStream Responseを返す際にSet Cookieが正常に行えない場合がある不具合の修正
AWS LambdaのランタイムでStream Responseを返す際にResponseの headers
に set-cookie
を複数設定したとしても1つしか設定されないという不具合が修正されました。
上記の変更で 4.4.6 がリリースされています
4.4.6以降の修正
c.html
の返り値の型は引数に応じて Reponse
もしくは Promise<Response>
となるように修正
今までは c.html
の返り値の型が常に Response
もしくは Promise<Response>
となっていました。しかし、c.html
の第一引数が非Promise(例えば文字列)の場合は Promise<Response>
の返り値とならないように型修正が行われました。
4.4.6以降の修正 その2
hono/client
内で使用されているObjectのマージに関するテストをケース通り行うようにテストを修正
HonoにはRPC機能がありますが、その中で使用する hc
に関するリクエストの処理でクライアント側からオプションを追加で渡すことができます。その渡したオプションをデフォルトのオプションにマージしてリクエストを行うという deepMerge
という関数が内部に存在しますが、そのテストに関する修正です。
振る舞いとしては Object ではないオプションが渡された場合はそのオプションをそのまま投げるという処理になっていますが、テストケースが正常に実行されるようにテストが修正されました。
同一のテストケースの削除
Honoが独自に定義する Request(HonoRequest)
で .text()
や .json()
などRequestのBodyから指定の形式でデータを取得する処理のテストが重複して定義されていたのが削除されました。
4.4.6以降の修正 その3
ContextVariableMap
と Env(Variables)
と同名のキー定義がある場合に Env
の型を ContextVariableMap
の型で上書きしてしまう不具合修正
HonoのContextには ContextVariableMap
という型定義があります。これはmiddlewareなどで Context に値を設定する場合に定義するものですが、これが middleware に定義した Variables
の型定義を壊してしまうというものの修正です。文字を読んだだけではわからないので、PRにあったコードを拝借して説明します。
declare module 'hono' {
interface ContextVariableMap {
test: 'root'
}
}
const middleware = createMiddleware<{
Variables: {
test: 'override'
}
}>(async (c, next) => {
c.set('test', 'override')
await next()
})
まず ContextVariableMap
で test
というキーに root
という文字列が入るという型定義をしています。次に createMiddleware
は Variables
つまり Env
の型定義に同名の test
というキーで override
という文字列を設定しているという型定義の2つを作成します。
const router = new Hono()
.get(
'/test',
middleware,
async c => {
const testValue = c.get('test') // test type is 'root'
return c.text(testValue) // However, the testValue variable contains `override`.
},
)
c.get
で test
というキーでデータを testValue
の変数に格納しています。この時 testValue
の型は root
という文字列の型になるが、実際には override
という文字列が入っているというのが今回の不具合の内容です。
上記の変更で 4.4.7 がリリースされています
4.4.7以降の修正
変数に明示的に型を設定
hono/jsx
内部で使用する変数に明示的に型を設定する修正がされました。これはJSRがslow typesになっている警告を修正するものです。要は型を推論に任せるよりも明示的に設定した方が型の決定が早くなるために行ってほしいというものらしいです。
Codecovを動作させるためのトークンの環境変数の設定方法を変更
HonoにPull Requestを作成した場合に Codecov
によるカバレッジの計測が行われていましたが、トークンが正常に設定されていないというエラーが発生していました。正しくトークンを設定するように修正されました。
JSDocのタイポ修正
ドキュメントのタイポが修正されました。
DenoのWebSocket接続時のOptionを設定できるように修正
DenoでWebSocket接続時にオプションを指定することができますが、DenoでHonoを使用する場合にWebSocket Helperではそれが対応されていませんでしたが、このコミットにより使用できるようになりました。
使用するには upgradeWebSocket
の第二引数に指定することで使用できるようになります。
app.get(
'/ws',
upgradeWebSocket((c) => {
return {
onMessage(event, ws) {
console.log(`Message from client: ${event.data}`)
ws.send('Hello from server!')
},
onClose: () => {
console.log('Connection closed')
},
}
}, { idleTimeout: 60 })
)
4.4.7以降の修正 その2
Accepts Helper内で行うリクエストヘッダーのパース処理速度を更に向上させる修正を実施
HonoにはAcceptsヘッダーを処理するためのヘルパーが存在します。内部の処理ではRequest Headerに設定されているAcceptsの内容を読み取る時に、スプレッド構文を用いて、以下のようにAcceptをパースしています。(実際のコードとは少し異なるが似たようなサンプルです)
const acceptHeader = c.req.header('Accept') // Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8
const accepts = acceptHeader.split(',') // ['text/html', 'application/xhtml+xml', 'application/xml;q=0.9', 'image/webp', '*/*;q=0.8']
return accepts.map((accept) => {
- const [type, ...params] = accept.trim().split(';') // ['application/xml', 'q=0.9']
+ const parts = accept.trim().split(';') // ['application/xml', 'q=0.9']
+ const type = parts[0]
...
}
この処理の中で重み値である ;
の除いた実際の値を取得するための処理をスプレッド構文を使うより1つの配列に一旦格納してから実際の値を取得するといったコードの方がパフォーマンスが向上するということで変更が行われました。
4.4.7以降の修正 その3
utils/buffer.ts
のテストカバレッジをあげるためにテストを追加
utils/buffer.ts
の中に equal
という関数がありますが、これはHonoの中では使用されていません。しかし、ユーザが使用するかもしれないということで残す決定をしましたが、それならば振る舞いを保証する必要があるためテストコードが追加されました。
Bunのテストでは標準機能を用いてLCOV形式のカバレッジレポートを生成するように修正
Bunは1.1.16からテスト実行におけるカバレッジのレポートをLCOV形式で出力できるようになったようです。そこでBunの環境では1.1.16にバージョンをあげて、テストによるカバレッジレポートをBun標準の機能を用いて出力するように変更されました。
テストコードにおけるVitestの不要なimportを削除
HonoのテストではVitestが使用されていますが、Vitestの describe
や it
といったAPIはglobalsの設定がされているので、 import
は特に必要ありません。そこで import
してしまっているテストから不要なVitest import
を削除する修正されました。
4.4.7以降の修正 その4
指定された2つの値をそれぞれハッシュ化する関数を並行処理するようにしてパフォーマンスを改善
Basic Auth MiddlewareやBearer Auth Middlewareでは渡されたユーザ名やパスワード、トークンといったものが設定値と同等かどうかを調べるために timingSafeEqual
というHono内部で使用する検証関数が存在します。その timingSafeEqual
の関数では渡された値とハッシュ化する関数を通して値が2つの値が同値になるかという処理がありますが、それぞれ直列処理していたコードを並行処理に変えてパフォーマンスをあげるという変更が行われました。コミット内容そのままですが以下の変更です。
- const sa = await hashFunction(a)
- const sb = await hashFunction(b)
+ const [sa, sb] = await Promise.all([hashFunction(a), hashFunction(b)])
上記の変更で 4.4.8 がリリースされています
4.4.8以降の修正
Context生成時にHonoRequestオブジェクトを事前に生成して保持するのではなく、必要時に生成するように修正
Request毎にHandlerで使用するContextを生成しますが、生成時にオリジナルのRequestオブジェクトからHono独自のRequestオブジェクトつまり、 HonoRequest
というオブジェクトを生成してそれをContextに設定していました。しかし、これは使用しなれば無駄な生成コストであるため、処理の開始速度を早めるためにContextの初期では HonoRequest
を生成せず、 HonoRequest
を取り出す時に生成するようにしました。これにより HonoRequest
を使用しないリクエスト処理時間が早くなります。
よくある手法ですが、以下のようにプライベートな変数に生成した結果を保持しておき、2回目以降は変数にすでに生成済みの結果を返すようになっています。
get req(): HonoRequest<P, I['out']> {
this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult)
return this.#req
}
ミドルウェアを使用してルートをChainしていくとContextの型が正しくなくなる不具合を修正
Issueにあったコードを拝借して説明します。
import { Hono, MiddlewareHandler } from 'hono'
const mw1: MiddlewareHandler<{ Variables: { foo1: string } }> = async (c, next) => {
c.set('foo1', 'foo1')
await next()
}
const mw2: MiddlewareHandler<{ Variables: { foo2: string } }> = async (c, next) => {
c.set('foo2', 'foo2')
await next()
}
const app = new Hono()
.get('/1', mw1, async (c) => {
// this is correctly typed.
return c.json({ foo1: c.var.foo1 })
})
.get('/1-then-2', mw1, mw2, async (c) => {
// this is also correctly typed.
return c.json({ foo1: c.var.foo1, foo2: c.var.foo2 })
})
.get('/nothing', async (c) => {
// In this scope, c.var should be empty because no middlewares are applied.
// However, c.var is typed as { foo1: string; foo2: string; }.
// In runtime, v is {}.
const v: { foo1: string, foo2: string } = c.var;
return c.json(v);
});
コメントそのままですが、上記のコードでいう /nothing
にアクセスすると返ってくる値は {}
というカラのJSONが返ってきます。しかし、コード上の c.var
はカラではなく、しっかり型が入っているというバグが以前ありました。
このバグはバージョン4のリリースと同時に修正されましたが、別に型の修正がされたことで再度同じバグが引き起こされたようです。その修正が行われました。
Web Standardsで動作する説明文に変更
ここ最近「Edge」というのは私も使用しなくなってきたのですが、Honoも「Edge」で動作するという説明ではなく、Web StandardsのAPIで動作するフレームワークですよという説明文にREADMEなどが修正されました。
Server-Timing Middlewareが重複して動作するとエラーとなってしまう不具合の修正
HonoにはServer-Timingのヘッダーを設定してくれるServer-Timing Middlewareが存在します。
しかし、このミドルウェアを app.route
などの機能を用いて、2つのルーティングで重複して使用するとエラーになるという不具合が修正されました。
import { timing } from 'hono/timing'
import { Hono } from 'hono'
const app = new Hono()
app.use(timing())
const a = new Hono()
a.use(timing())
a.get('/', (c) => c.text('a'))
app.route('/a', a)
export default app
上記の変更で 4.4.9 がリリースされています
4.4.9以降の修正
JSRでのJWTにあるユーティリティの型が読み込めない不具合修正
HonoのJWTには JWTPayload
や SignatureAlgorithm
といった型が存在しますが、JSRを使ったHonoではその型が正常に取得できないという不具合が修正されました。
4.4.9以降の修正 その2
ReadableStream
の接続が切断された場合に明示的に abort
を呼び出すように修正
Bunで
Bunでは SSE などの ReadableStream
で接続している場合にクライアントで画面を閉じるなどといった切断処理起こった場合に ReadableStream
のキャンセル関数が呼び出されないようです。そのため、キャンセル関数でユーザ側で定義した abort
処理が動作しないということが発生するようです。
そこで AbortSignal
の abort
イベントでもユーザが定義した abort
を呼び出すように修正されました。
先頭にスラッシュから始まらないルーティングを定義した場合にHono RPCクライアントが正しい型を返さない不具合の修正
HonoにはRPCのようにレスポンスのルーティングとレスポンスの型を明示的に行える機能があります。その機能を用いる際に、ルーティングに設定するパスをスラッシュから始めないと型が正常に動作しないという不具合が修正されました。
const route = app.get('posts', (c) => {
return c.json({
test: 'test'
})
})
export type AppType = typeof route
import { hc } from 'hono/client'
const client = hc<AppType>('/')
client.posts.$get // <-- Incorrect type
上記の変更で 4.4.10 がリリースされています
4.4.10以降の修正
routerのテスト関数が非同期である必要のないものは通常の関数定義に修正
テストの it
に渡すテスト関数が非同期関数として定義されているものの中で非同期である必要の無いものから async
を消すという修正がされました。
1つのルーティングに2つ以上のハンドラーを定義すると 2つ目以降はFormDataをRecord型として値を受け取れない不具合の修正
hono/validator
を使用すると form
として指定するとFormDataをRecord側で受け取ることができます。しかし、2つ以上定義すると2つ目以降はFormDataがそのままFormDataとして渡されてRecord型として値が受け取れない不具合が修正されました。
原因はリクエストから受け取ったFormDataをRecord型に変換して返す処理の中で2回目以降のリクエストからFormDataを取り出す処理を高速化するためにFormDataをキャッシュしているようですが、そのキャッシュの設定に設定したFormDataをそのまま返してしまうロジックが存在したため発生するようです。
import assert from 'assert'
import { Hono } from 'hono'
import { validator } from 'hono/validator'
const app = new Hono().post(
'/',
async (c, next) => {
await c.req.parseBody()
await next()
},
validator('form', (value) => {
console.log('validator - value:', value)
assert(!(value instanceof FormData), 'Value has to be a Record, not FormData')
return value
}),
(c) => {
return c.text('Hello Hono!')
}
)
const form = new FormData()
form.append('foo', 'bar')
await app.request('/', {
method: 'POST',
body: form
})
hono/client
を使用してWebSocketを接続する際にQuery Parametersをサポートするように修正
hono/client
を使用してエンドポイントに対してWebSocketのリクエストを投げる際にQuery Parametersを渡して接続できるように変更が加えられました。これによりサーバ側はエンドポイントだけでなく、渡されたパラメータにより処理を振り分けることが可能となりました。
const client = hc<AppType>('http://localhost')
client.index.$ws({
query: {
id: '123',
type: 'test',
},
})
// => ws://localhost/index?id=123&type=test
ルーティングに定義するパスとハンドラーの組み合わせの全パターン型指定の修正
ちょっと正直これだけ見ると正直難解な型定義の修正なのですが、つまるところHonoには app.get
の引数にパスと複数のハンドラーを渡すことができますが、その渡せるハンドラーの個数9個分の型定義を直すリファクタリングが行われたようです。
テスト対象の名称のタイポを修正
getRouterName
を対象としたテストの description
が誤っていたため修正されました。
4.4.10以降の修正 その2
ReadableStream
が正常終了した場合に onAbort
が呼び出されてしまう不具合修正
denoで
この記事の「4.4.9以降の修正 その2」でも触れたBunで ReadableStream
が切断された場合に onAbort
が呼び出す修正を触れたと思いますが、その修正でBunは確かに問題なくなったのですが、denoの環境下では正常終了した場合も onAbort
が呼ばれてしまうという不具合が発生したようです。
そこで明示的に close()
を呼んでいない場合は onAbort
を呼び出すという修正がされました。
上記の変更で 4.4.11 がリリースされています
4.4.11以降の修正
Set-Cookie
にカンマが入るような設定を行った場合に正しく Set-Cookie
が返らない不具合の修正
AWS-LambdaのAdapterで
PRにかかれていますが、例えば Set-Cookie
の値に Expires
を設定すると以下のような内容になります。
Set-Cookie: key=value; path=/; expires=Wed, 10-Oct-12 07:12:20 GMT
AWS-LambdaのAdapterではHonoで設定した Set-Cookie
をAWS LambdaのResponseとして返す処理でCookieの値を再設定しています。そこでHonoで設定した Set-Cookie
にカンマが入るような設定をすると正常に Set-Cookie
の値が返らないという不具合が修正されました。
またこの修正でHeaderから Set-Cookie
の値を取得するために、 getSetCookie
というAPIを使用できる場合は使用するという風にも変更されています。
use
指定後のHttp Method定義にパスを指定しない場合にURL Parameterの型が正しく取得できない型定義の修正
同一のパスに対して、POST
と GET
の両方のHttp Methodを受け取るルーティングを定義する場合はチェインして記述することが可能です。更にチェインした側はパスを省略することでチェインされた側のパスを自動的に引き継ぎます。
new Hono()
.post("/:id", async (c) => {
const id = c.req.param("id");
return c.text(id);
})
.get((c) => { // path is "/:id"
const id = c.req.param("id");
return c.text(id);
});
しかし、use
を使用するとpathは引き継ぐのは引き継ぐのですが、型が正しく認識できないという型の不具合が修正されました。
new Hono()
.use("/:id", async (c, next) => {
await next();
})
.get((c) => { // path is "/:id"
const id = c.req.param("id");
return c.text(id); // TypeScript complains that `id` might be `undefined`.
});
4.4.11以降の修正 その2
JSDocの hono.dev へのドキュメントページリンクを修正
JSDocには hono.dev へのドキュメントページのリンクが記載されています。各機能のドキュメントページのURLが /docs
変更されたため、JSDoc内のリンクも /docs
へのリンクへと変更されました。
4.4.11以降の修正 その3
download
属性にbooleanの値を設定した場合に属性自体の出力有無となるように修正
アンカータグの
アンカータグには download
という属性値があり、この属性値はリンク先を download
属性値で指定した名前で保存するというものです。 hono/jsx
で download
属性値にbooleanの値を設定するとそれがそのまま文字列として出力されていましが、この変更により true
の場合はただ download
属性値を出力し、 false
の場合は download
属性値を出力しないという風に変更されました。
triage
ラベルとするように変更
HonoへのIssue作成の際にBug Reportを作成された場合は
今まではBug ReportのIssueを作成された場合は即座に bug
のラベルが付与されていましが、まずは triage
ラベルが付与されるように運用が変更されるようです。その後に調査した結果でバグだった場合は bug
ラベルを付与する運用に変更されます。
c.json
で返る型を JSON.stringify()
で返る型に限りなく近くする変更
Honoでは c.json
をハンドラーで返すことでJSONのデータをクライアントに返すことができます。またHonoではRPCで処理するための hono/client
が存在します。 hono/client
で使用する hc
はハンドラーが返す c.json
の返り値から型を決めますが、JSON.stringfy
にはObjectではなく、Functionを渡したり Symbol
を渡したりと無茶なことをすると undefined
や カラのオブジェクト( {}
)を返しますが、その動作に近くなるように型変更が行われました。
slow types
となる変数に明示的に型を指定するように修正
JSRリリースのための
JSRリリースするために slow types
となる変数に明示的に型を指定するように修正がされました。
utils/jwt
にJSDocを追加
JSRのスコアを向上させるために
JSRにはパッケージのスコアリングに「ドキュメント」「ベストプラクティス」「発見可能性」「互換性」の4つの項目がありますが、HonoのJSRのスコアを上げるために utils/jwt
にJSDocが追加されました。
上記の変更で 4.4.12 がリリースされています
ベンチマーク計測を行うため、他Routerライブラリバージョンを更新
Honoと他のRouterライブラリとの速度比較を行うために最新版で速度を測るように express
や koa-router
などなどのライブラリを最新バージョンで速度を測るように変更されています。
4.4.12以降の修正
HonoのビルドをBunで行うように修正
Honoのビルドは一部Bunを使用してビルドされていました。しかし、一部はNode.jsでTypeScriptを実行するために tsx
も併用されていました。Bunでのビルドが統一されるならば tsx
の使用や2つのRuntimeは必要ないので、Bunに寄せるように修正されたようです。
4.4.12以降の修正 その2
UnOfficalStatusCode
の型を使用しないようにするリファクタリング
deprecatedな
「4.4.2以降の修正 その4」でも触れていますが、 UnOfficalStatusCode
は deprecatedです。(予定ではv5で削除されるようです)内部で UnOfficalStatusCode
の型が使用されていますが、結局のところ型としては UnofficalStatusCode
と同様なので、 UnOfficalStatusCode
は UnofficalStatusCode
と定義するように修正されました。書いてて伝わりにくいのでコードで書くとこうです。
- export type UnOfficalStatusCode = -1 // same UnofficialStatusCode
+ export type UnOfficalStatusCode = UnofficialStatusCode
4.4.12以降の修正 その3
th
タグの scope
属性の指定できる正確な属性値をUnion型の定義を追加
hono/jsx
で作成する th
タグの scope
の属性値は String
が指定可能でした。ただ、scope
に指定する属性値は row
や col
といった決まった値を指定します。そこで指定する属性値の型に row
や col
といった指定できる4つの属性値のUnion型が追加されました。
ただし、この4つの属性値以外にも String
での指定は可能です。これは下位互換もあるかもしれませんが、4つの属性値以外も一応ブラウザでの動作があるので今まで通りの値も指定が可能になっています。
RPCのFormの属性値に配列を指定するとエラーになる型情報の修正
hono/client
を使用してRPCによるFormを送信する際に、本来Formは属性値に配列データを指定することが出来ますが、HonoのRPCでは配列を使用すると型エラーが発生する型情報の修正が行われました。
Issueにあったコードを拝借すると以下のような場合にエラーになるようです。
import { Hono } from "hono";
import { hc } from "hono/client";
import { validator } from "hono/validator";
const route = new Hono().post(
"/",
validator("form", (value: { body?: string[] }, c) => {
const body = value["body"];
if (!body || !Array.isArray(body)) {
return c.text("Invalid!", 400);
}
return { body };
}),
(ctx) => {
return ctx.text(`Body is [${ctx.req.valid("form").body}]`)
}
);
const client = hc<typeof route>("");
client.index.$post({
form: {
body: ["1", "2", "3"], // this is type error
},
});
4.4.12以降の修正 その4
Blob
を指定できるように型を変更
RPCのFromに
昨日の 4.4.12以降の修正 その3 で行われた「RPCのFormの属性値に配列を指定するとエラーになる型情報の修正」に付随して、Formに指定できるのは File
型ではなく Blob
型が良いということで Blob
型を指定できるように変更されました。
ちなみに File
と Blob
の違いは Blob
の型に対して name
と lastModified
のプロパティを持つことで File
型になります。(他に2つのプロパティがありますが、非推奨だったりします)
余談ですが、この File
から Blob
への変更の方がいいのではないかという議論は作者はもとより中学生たちで議論されてて関心するばかりです。
use
のパスにワイルドカードのパスを指定したミドルウェアを設定するとRPCの型が正常に生成されない型の不具合を修正
Honoには use
というミドルウェアを設定するものがありますが、この use
にワイルドカード、つまり *
を指定するとRPCの型が正常に生成されないという型の不具合がありましたが、それが修正されました。
const app = new Hono();
app.use('*', middleware).route('/users', usersRouter);
const client = hc<typeof app>('');
console.log(client.users.$get()); // type error (Property '$get' does not exist on type 'never'.)
上記の変更で 4.4.13 がリリースされています
4.4.13以降の修正
Honoのv4.5がリリースされたので、その修正およびコミットが以下のPRに纏まっています。
数日はここからコミットの内容を書きつつ、mainブランチに追いついていく記載とします。
@hono/react-compat
パッケージのために createRoot
と hydrateRoot
をデフォルトエクスポートに変更
HonoもPreactのように @hono/react-compat
というライブラリを使用すると import xx from 'React'
がReactを使用するのではなく、 hono/jsx
を使用するということが出来るようになるための修正が行われました。
@hono/react-compat
パッケージのために React互換のrenderToString
と renderToReadableStream
を追加
上記の修正と同じように @hono/react-compat
を指定するということはReact互換のAPIが必要になってきます。そこで hono/jsx
にもReactと同じ振る舞いを行う renderToString
と renderToReadableStream
が実装されました。
useCallback
の引数の関数に引数を取る関数を指定すると型エラーとなるため型を修正
これもReactとの互換性向上の1つだと思いますが、 useCallback
の第一引数に関数を渡しますが、その関数が引数を取るような関数を渡すと型エラーとなっていたようです。そこで型エラーが発生しないように修正されました。
また、Reactの StrictMode が動作するようにJSXの記述ができるように修正も同時に行われています。
JWT Auth Middleware で署名付き Cookieを使用できるように修正
HonoのJWT Auth Middlewareでは署名付き Cookieを扱うことができず、ミドルウェアが401で応答を返していました。この変更によりJWT Auth Middlewareでも署名付き Cookieを使用できるように修正がされました。
余談ですが、この修正自体は元は別の方が行っていたようですが、PRが停滞していたため別の方が引き取って続きを作成したようです。停滞しているPRをこのように引き取る形もありですね。
hono/jsx
バージョン番号を更新
v4.5で hono/jsx
のバージョン判定文字列が 19.0.0-hono-jsx
に変更されました。
createContext
をReact同様にProviderとするように修正
これも @hono/react-compat
を実現するための変更です。Reactのエイリアスとして動作するようにReact同様の動作をする必要があるので、作成したContextはProviderとして動作するように修正されました。
React 19の新機能と互換性を持つための大幅な変更
これはかなり大作なコミットです。
React 19では色々と新機能が入っています。中でもこのコミットで対応されたのは数多くあります。
- headタグ内の
title
やmeta
などのタグの巻き上げレンダリングをサポートの追加 - refsのクリーンアップ関数対応のサポートの追加
- 非同期スクリプトのサポートの追加
-
useActionState
などのFormに関するHooks関数のサポートの追加 -
use
関数のサポートの追加
書いてる私もお腹いっぱいになってきます。これも最終的には @hono/react-compat
を実現するためのものにもなると思います。まだ私自身も試したわけではありませんが、 use
がサポートされているということは非同期コンポーネントも hono/jsx
で使用できるということになるのでしょうか。
続きは別途記載していきます。
4.4.13以降の修正 その2
undefined
を返すように修正
ConnInfo HelperのIPアドレスタイプの判定が行えない場合は
今まではIPアドレスのタイプが IPv4
もしくは IPv6
のどちらか、もしくは判断できない場合は unknown
という文字列を返していました。(IPアドレスの取得ができないというわけではなく、IPアドレスのタイプということ)
しかし、Cloudflare Workersで動作させると常に unknown
という文字列を返すようです。そこで、IPアドレスのタイプが不明な場合は取得できたIPアドレスからタイプを逆引きするという提案もありましたが、IPアドレスのタイプが取得できないのあれば無理に作成せず undefined
を返すという方向で修正がされました。
ちなみにIPアドレスのタイプはどのように取得しているかというとBunだけは送られてきたRequestオブジェクトからIPアドレスやIPアドレスタイプが取得できるようです。逆にBun以外はIPアドレスのタイプは取得できないので、IPアドレスから逆引きするしか無いと思います。
4.4.9で修正された影響により4.5のブランチでテストが失敗してるテストコードの修正
ちょっとコミットの解釈は自信が無いですが、たぶん合ってると思います。(PRなど何も説明がないので自信の記憶だけが頼り)
4.4.9のリリースに入ってる「Context生成時にHonoRequestオブジェクトを事前に生成して保持するのではなく、必要時に生成するように修正」というのがあります。この記事の上の方に解説しているので見て頂ければわかると思います。
これの影響で4.5リリースのブランチにあるテストが失敗してしまっていたので、4.4.9リリースと同様の修正がテストコードにて行われました。
React Compilerによる再レンダリングの抑制するための修正
なんかタイトルが雑ですが、雰囲気で感じとってください。
hono/jsx
は(特にHono v4.5)ではReact 19互換に力が入っています。そこでReact互換であるならばReact Compilerで実行することより同一のPropsであれば子の再計算処理が行われない(つまり、自動的にmemo化された状態)になるはずが、 hono/jsx
では再計算されてしまうという事象がありました。そこでその事象を修正したのがこのコミットです。
修正としては、元からのJSXのProps数やPropsの値を現在のPropsの設定を見比べて、同一の場合は比較処理をスキップするという処理が入ったようです。
Cloudflare Pages用のmiddlewareの追加
HonoにはCloudflare PagesのAdapterはありますが、middlewareはありませんでした。Issueで提案された面白い例ではmiddlewareではCloudflareのHTMLRewriterでのHTML書き換え処理をmiddlewareで共通的に定義するというような使用用途が提案され承諾されて追加されました。
// functions/_middleware.ts
import { getCookie } from 'hono/cookie'
import { handleMiddleware } from 'hono/cloudflare-pages'
export const onRequest = handleMiddleware(async (c, next) => {
const myCookie = getCookie(c, 'my_cookie')
const response = await next()
// Alternative API similar to Pages middleware
const response = await c.next()
return new HTMLRewriter()
.on('head', new InjectScriptHandler(myCookie))
.transform(response)
})
Cloudflare Pagesのhandlerの型を追加したCloudflare Pages用のmiddlewareのhandlerと同様に修正
追加されたCloudflare Pages用のmiddlewareではCloudflare Pages用のhandlerの型が定義されていましたが、元からあったCloudflare PagesのAdpaterではhandlerの型定義が少し異なっていました。そこで追加されたmiddlewareのhandlerの型定義をAdpater側でも使用するように修正されました。
続きは別途記載していきます。
4.4.13以降の修正 その3
undefined
を追加
ConnInfo Helperが返すIPアドレスタイプの型に
前回の「4.4.13以降の修正 その2」でも説明したConnInfo HelperのIPアドレスタイプですが、型自体に undefined
が追加されました。これは値が undefined
ということではなく、そもそもオブジェクトに addressType
というものがオプショナルで返ってくるものなので undefined
という型が追加された形になります。
IP Restriction Middlewareを追加
そのままですが、要はIP制限を行ってくれるIP Restriction Middlewareというミドルウェアが追加されました。
ドキュメントの通りですが、このミドルウェアでは拒否するリストを denyList
に、許可するリストを allowList
に登録することで指定のエンドポイントをIP制限をかけることができるようになります。まだまだこういったIP制限を行うアクセス制限はまだまだあると思うので十分需要はあると思います。(昔自分もFastifyのプラグインとして作った記憶があります)
import { Hono } from 'hono'
import { getConnInfo } from 'hono/bun'
import { ipRestriction } from 'hono/ip-restriction'
const app = new Hono()
app.use(
'*',
ipRestriction(getConnInfo, {
denyList: [],
allowList: ['127.0.0.1', '::1'],
})
)
app.get('/', (c) => c.text('Hello Hono!'))
察しのいい方は気づいていると思いますが、HonoでIPアドレスを扱うにはConnInfo Helperが必要になりますが、このIP制限を行うミドルウェアももちろんIPアドレスを扱うのでConnInfo Helperに依存しています。
IP Restriction Middlewareが返す無名関数に関数名を追加
IP Restriction Middlewareが返す関数が無名関数だったため、関数名を定義して返すように修正されました。これでミドルウェアからの返り値を名称をもって取得できるようになります。
ConnInfo HelperがVercel上で動作するように修正
ConnInfo Helperは様々な実行環境でのIPアドレスの取得を吸収するものですが、VercelはVercelでまたIPアドレスの取得方法が異なります。このコミットではVercel AdapterでのIPアドレスの取得が行えるに修正がされました。
VercelはこのHeaderからIPアドレスが取得できますが、これを見ると確かにそこからですよねって感じのわかる人はわかるヘッダーの値です。
undefined
に修正
Vercel Adapterで返すIPアドレスタイプを
追加されたVercel AdapterでのConnInfo HelperでIPアドレスタイプが旧の unkwon
の文字列を返すようになっていたので、直近変更された undefined
で返すように修正されました。
ConnInfo HelperがLambda Edge上で動作するように修正
これもConnInfo Helperシリーズの修正ですが、Lambda EdgeのAdapterでIPアドレスが取得できるように修正されました。
Service Worker Adapterの追加
いわずもがなHonoはバックエンドサーバとして使用されることが多いですが、HonoをService Workerとして動作させることを可能とするAdapterが追加されました。これは一種のHonoがWeb Standards APIで作成されているのでこういうことが可能ということです。
このService Worker Adapterを使用するとオフラインで動作するWebアプリケーションの構築が行えるということでこれはこれで面白いものが追加されたと思います。
リクエストごとに一意のIDを採番するRequest ID Middlewareの追加
追加したものを見ていてRuby on Railsにもあったなと懐かしい気持ちになってきました。
Honoでリクエストごとに一意にIDを採番してくれるミドルウェアが追加されました。パッと聞いただけでは使用用途がわからないかもしれませんが、よくある使用例でいうとログに仕込むことで、そのリクエストがどのような処理を通ってリクエストが処理されたかというのがわかるようになります。それがこのミドルウェアを使用すると簡単に採番されたIDが取得できるようになります。
ちなみにドキュメントにも書いていますが、IDの採番はデフォルトで crypto.randomUUID()
を使用します。そのため、環境によっては動作しない可能性もありますが、変更することも可能になっています。
複数のミドルウェアの実行結果を制御するCombine Middlewareの追加
ミドルウェアは色々と存在しますが、複数使用することも想定されます。そこで使用するミドルウェアの全部を実行する必要がない場合などにはこの新しく追加されたCombine Middlewareが大いに役立ちそうです。
このミドルウェアは some
, every
, except
の3つの機能を持つようで、ドキュメントにも書いていますが、some
でIP制限のミドルウェアとベーシック認証にミドルウェアでどちらかが正常に通ればアクセスできるエンドポイントをこのCombine Middlewareを使用することで構築できるようになります。現実世界では例えば社内や特定のプライベートネックワーク内からであれば無条件でアクセスを許可しつつ、パブリックネットワークからはベーシック認証がかかるということができるということです。
import { Hono } from 'hono'
import { bearerAuth } from 'hono/bearer-auth'
import { getConnInfo } from 'hono/cloudflare-workers'
import { some } from 'hono/combine'
import { ipRestriction } from 'hono/ip-restriction'
const app = new Hono()
app.use(
'*',
some(
ipRestriction(getConnInfo, { allowList: ['192.168.0.2'] }),
bearerAuth({ token })
)
)
app.get('/', (c) => c.text('Hello Hono!'))
Bindings
に interface
を指定できるように型を修正
Honoのジェネリックである
HonoにはBindingというContextつまりDIを設定するジェネリックを指定できる型に Bindings
というものがあります。これは今まではTypeScriptの type
しか指定できませんでしたが、 interface
も指定できるようにするというのがこの変更です。
PRでも触れられていますが、この変更の起点となったのはCloudflare Workersでは Env
の型を取得するcliコマンドがありますが、このコマンドを使用して生成した型は interface
で定義されているためそのまま使用することができるようになるというのが利点として書かれています。Cloudflareユーザには嬉しい変更だと思います。
追加されたIP制限やミドルウェアの組み合わせミドルウェアの使用例などに関するコメントを正しいコメントに修正
exampleなどに書かれているコメントに from
先が正しくないものがあったりJSDoc自体の追加だったりとコード内のコメントに関する修正がされました。
ContextVariableMapに配列型のものを指定すると型が正しく取得できない場合がある不具合の修正
発生条件まで詳しく見ていないですが、ContextVariableMap
の値に配列の型を指定すると c.get
して取り出したものの値の型が any
になってしまうという不具合が修正されました。
hono/jsx
でHTMLのグローバル属性の型のサポートを追加
HTMLにはグローバル属性というすべてのHTML要素で共通の属性があります。その属性を指定する場合の型のサポートが追加されました。
JSRリリースのための slow types となる変数に明示的に型を指定するように修正
毎度お馴染みのJSRのslow typesとなる警告の修正です。
上記の変更で 4.5.0 がリリースされています
これでv4.5のリリースの変更がすべて大体mainブランチの変更に追い付いたと思います。(今日1つだけマージされていますが、コードの変更ではないので明日の解説に回します)
4.5.0以降の修正
ビルド時のファイル削除をライブラリを使用しないように修正
ビルド時に前回のビルドをクリーンアップするために rimraf
を使用して rm -rf
と同等の処理を実施していました。ビルドはBunで行っていますので、Bun Shellにそれと同等のことができるcliが存在するのでそれを使用して依存関係を減らすように修正されました。
src/
配下から移動する修正
テスト用のコンフィグファイルを
テスト用コンフィグファイルは src/
配下に配置しない方がよいということで、vitestの設定ファイルである setup-vitest.ts
ファイルが移動されました。
4.5.0以降の修正 その2
secret
プロパティに JsonWebKey
や CryptoKey
の型の値も指定できるように型を修正
JWT Auth Middlewareの引数の
jwt
の引数に secret
というプロパティには今まで文字列のものしか指定できませんでしたが、その先の内部でJWTを verify
するメソッドは文字列だけでなく、 JsonWebKey
や CryptoKey
も渡すことができるので、ミドルウェアのそもそもの jwt
の secret
も JsonWebKey
や CryptoKey
を渡すようにしてもよいという修正です。何か動作自体が変わることはありません。
Bearer Authの値のprefixが無い状態も動作するようにする
Bearer Authの値は特に指定しなれば Bearer {token}
という風に Bearer
というprefixがある前提で動作します。このprefixを変更することはできますが、prefix自体を無しにするということを可能にするというのがこの修正です。
この変更により以下のような動作が可能です。
app.use('/apiKey/*', bearerAuth({ token, prefix: '', headerName: 'X-Api-Key' }))
app.get('/apiKey/*', (c) => {
handlerExecuted = true
return c.text('auth apiKey')
})
const req = new Request('http://localhost/apiKey/a')
req.headers.set('X-Api-Key', 'hoge')
const res = await app.request(req)
console.log(await res.text()) // output auth apiKey
factory.createApp()
をStableに変更
factory.createApp()
は今まで experimental でしたが、stableに変更されました。
WebSocketのクエリパラメータの配列をサポートするに修正
「4.4.10以降の修正」であったWebSocketのクエリパラメータをサポートしましたが、配列のパラメータがサポートされていなかったため、この修正で配列もサポートされるように修正されました。
Content-Type
と validator
のタイプが一致しなくてもエラーをスローしないように修正
Requestの
今までの validator
の振る舞いとして第一引数に json
という文字列を指定した場合はRequestの Content-Type
が application/json
でない場合はエラーとしていました。しかしRequestの Content-Type
が ultipart/form-data
やそもそも Content-Type
が指定されていない場合もエラーになるのは使い勝手としてあまり良くないためvalidatorは Content-Type
が一致しない場合は何も行わないという変更がされました。
上記の変更で 4.5.1 がリリースされています
4.5.1以降の修正
getRuntimeKey()
が other
になってしまわないように修正
Cloudflare Pagesで
どうやらCloudflare Pages(のProduction?)では getRuntimeKey()
の値取得のロジックに使用している navigator.userAgent
もっというと navigator
が使用出来ないために、ランタイムキーの判定が正しくないということが発生するようです。そこでエラーにならないように修正されました。
ただしこの修正の元となっているのはCloudflare Pagesで c.env
が正しく取得出来ない場合があるというIssueが元になっているようで、この修正でなぜ直るかまでは理解出来ていません。また c.env
が正しく取得出来ないのは Cloudflare Workersのバージョンである compatibility_date
を更新することで直るということも報告されているので、ちょっと問題としてはややこしそうです。
4.5.1以降の修正 その2
c.json
で readonly
が設定されたプロパティの型が正常に返らない不具合の修正
4.4.11以降の修正 その3に記載した「c.json
で返る型を JSON.stringify()
で返る型に限りなく近くする変更」の修正を行いましたが、readonly
の型が正しく返らない不具合が修正されました。
昨日の「Cloudflare Pagesで getRuntimeKey() が other になってしまわないように修正」をリバート
やはり修正の起因は c.env
の値が正常に取得出来ないということらしいですが、内容を読む限りCloudflare Workers上の問題であるように感じ取れます。昨日も書きましたが compatibility_date
で正常に動作するCloudflare Workersのバージョンを指定すると良いということです。
TypedResponse
を使用した回帰するジェネリックの型指定を行うと c.set
の型が正しく行えないための修正
このスクラップを書いていて今まで1,2位を争うくらい意味がわからない修正です。そもそもこの修正を行う起因となったIssueで TypedResponse
というResponseの型をジェネリックで指定する型があるのですが、これを contextVariables
の型に使用して回帰するというかなりトリッキーな型指定をすることで c.set
の型がおかしくなるという報告の元に修正されています。
が、そもそもなんでこの修正で直るかというのすら理解できてないです。どちらかというと元の使用方法が使用想定にない型指定なのかなと思います。
4.5.1以降の修正 その3
CSRF Protectionのmiddlewareの返り値として返す関数名のTypoを修正
CSRF Protection というmiddlewareがHonoにはありますが、この import { csrf } from 'hono/csrf'
の csrf
が返す関数名が誤っているので修正されました。
4.5.1以降の修正 その3
X-Powered-By
を削除しないオプションを追加
Secure Headers MiddlewareでResponse Headersの
フレームワークでよく付与されるResponse Headersに X-Powered-By
というどのフレームワークで動作しているかを返す値がありますが、Secure Headers Middlewareを使用するとその値が自動的に削除されていました。そこで残すために removePoweredBy
というオプションに false
を渡すとReponse Headersの値を削除しないというオプションが追加されました。
上記の変更で 4.5.2 がリリースされています
4.5.2以降の修正
Content-Typeの文字列チェックにダブルクォーテーションも許すように修正
Bunなどでは boundary
の部分にダブルクォーテーションが入ることがあるようです。現状はContent-Typeの文字列チェックにダブルクォーテーションを入ることを許していないためエラーとなるそうです。そこでContent-Typeにダブルクォーテーションを許すように修正されました。
application/json
を指定しつつ、 charset
を指定するとvalidationされない不具合を修正
Content-Typeに
Content-Typeには application/json
という値の後ろに charaset
を指定できるそうです。(もちろん application/json
だけではありません。)
Content-Type: application/json; charset=UTF-8
hono/validator
でJSONのチェックを行う場合はContent-Typeの値が application/json
という値である必要があるのですが、 charaset
の値が入ってくる想定がされておらず、 application/json
という値で終わることつまり、後には文字列が入らない想定となっており、validationがスキップされる動作となっていたことが原因のようです。
そこで、application/json
の後ろに値が入ってきても問題ないように正規表現のチェック処理が修正されました。
Content-Typeをtypoしてるかと
恥ずかしい…修正しました!
4.5.2以降の修正 その2
hono/jsx
でSVGに関する不具合の修正
このコミットには2つの内容が含まれています。
- SVGの中の
title
タグを使用するとhead
タグのtitle
が追加される不具合の修正 - SVGの属性の中で、ケバブケースで出力されない不具合の修正
まず、1つ目はReact 19と同様の動作をするために4.5系で処理が追加されましたが、SVGの中に使用する title
タグを使用してしまうと同様の動作をする不具合が修正されています。またSVGの中にはキャメルケースとケバブケースの属性がありますが、 hono/jsx
やReactはそうですが、属性は基本的にキャメルケースで指定します。その指定した属性がケバブケースで出力されないという不具合が修正されています。
hono/jsx
のDOMのレンダリング速度の改善
hono/jsx
で1コンポーネント内でそれなりのDOMの数(Issueで報告があったのは <div><span></span></div>
が、ただ28個あるコンポーネント)をレンダリングする速度が遅くなるようです。どうやらDOMが増える度に指数関数的に速度が遅くなる。
原因としてはDOMを生成する処理にどこにDOMを差し込むかを判定する処理が再帰的かつループ処理があり、それにより計算コストが増大していくようです。無駄なループ処理が実行されないように修正されています。
Service Worker Adapterを使用してルーティングが存在しないURLにアクセスするとエラーが発生する不具合の修正
基本的にはルーティングに存在しないURLへのアクセスは404だったり、何かしらのエラーのレンダリング処理が行われますが、Service Workers Adapterでは存在しないルーティングにアクセスするとHonoでエラーが起きるようです。
Failed to execute 'fetch' on 'WorkerGlobalScope': Illegal invocation`
というようなエラーが発生して、Service Workerでの fetch
が動作しないというエラーが起きるようです。それについて暫定ではありますが、 globalThis.self
から fetch
が取得できるならその fetch
を使用するという処理で修正されています。
上記の変更で 4.5.3 がリリースされています
4.5.3以降の修正
hono/jsx
で draggable
属性値に string(true)
を設定すると型エラーとならないように修正
hono/jsx
では draggable
は boolean
または undefined
で受け入れる型定義になっています。そのため "true"
という文字列の設定が出来ないため、受け入れる型が変更されました。
ただ、変更された型が以下です。
- draggable?: boolean | undefined
+ draggable?: 'true' | 'false' | undefined
ちなみにReactの場合は boolean
でも受け入れます。
<div draggable={true}>react dragable</div>
// => output dom: <div draggable="true">react dragable</div>
このようにReactの場合は draggable
属性は Booleanish
という型つまり、 boolean
でも string
でも受け入れて文字列で出力するという処理がされています。なのでちょっと修正方法が微妙なようは気もします。
4.5.3以降の修正 その2
CSSProperties
という style
属性に指定できる型をオーバーライドできるように修正
hono/jsx
では属性の型をオーバーライドして独自の型を加えることが出来ます。 style
属性には CSSProperties
という型があるので、それをオーバーライドしても型が反映されないという不具合が修正されました。
合わせて、 style
属性には {}
のような構造化のデータを渡す型となっていましたが、文字列を渡すことができるようにも型が修正されています。
WebSocket再接続時の初期化処理を独自に定義できるように修正
今まではWebSocketの再接続時はHonoの内部で new WebSocket
という風に新しいWebSocketクラスを生成します。また、生成するWebSocketの接続URLはオプションで渡すクエリパラメータも含める必要があるので、元のWebSocketと異なる事ができ、型の安全性が失われることがあるということです。
そこで、この修正ではWebSocketの再接続するための関数を渡すことが出来るようになり、オプションも合わせて定義できることから上記の問題を解消するという変更がされました。
const client = hc<AppType>(url, {
webSocket(url, options) {
return new ReconnectingWebSocket(url, options)
},
})
validator
の 'param'
を指定しつつ、必須のパラメータが1つの定義と指定しているにも関わらず、オプションとなってしまう型不具合の修正
ちょっとタイトルからわかりにくいですが、元となったIssueから参考のコードを拝借します。
const schema = z.object({ id: z.string() })
const paramValidator = zValidator("param", schema)
// in: {
// param: {
// id: string | undefined; < -- The type undefined is wrong
// }
}
このように必ず入ってくる値にも関わらずMiddlewareでは undefined
という誤った型が入ってきてしまい、わざわざ undefined
の処理が必要になるということです。
上記の変更で 4.5.4 がリリースされています
4.5.4以降の修正
hono/jsx
で Fragment だけや null
を返した場合にカラ文字列のHTMLを生成するように修正
よくあるレンダリングしたくない場合にFragmentだけ( <></>
)や null
を返してカラのHTML文字列を生成することがありますが、hono/jsx
ではそれを行うとエラーになってしまっていたようです。そこでそれがエラーにならずカラのHTML文字列を生成するように修正されました。
c.header
に設定できる値を型でサポートするように修正
以下のようにHonoではResponseのHeadersに値を設定できます。
app.get('/', c => {
c.header('Content-Type', 'text/plain')
c.text('ok')
})
このResponseのHeadersのキーは標準でいくつかあり、例えばCORSを設定するならば Access-Control-Allow-Headers
などがあります。この設定できるキーの入力をある程度型でサポートするというのがこの修正です。確かにHeadersは色々あるので、こういう地味なのは嬉しいですね。
4.5.4以降の修正 その2
hono/jsx
の draggable
属性について boolean
型も指定できるように修正
これは以前で「4.5.3以降の修正」で私が書いたReactでは draggable
属性には boolean
が指定できるのでちょっと互換性が異なるなというものが修正されたようです。
要は 'true'
'false'
の文字列に加えて boolean
型も指定できるようになったようです。
4.5.4以降の修正 その3
c.header
に Content-Type
を指定した場合の値を型でサポートするように修正
「4.5.4以降の修正」の修正の c.header
の修正に更に追加されたものと思って大丈夫です。前回の修正はReponse Headersのキーに関する型のサポートでしたが、今回はそのキーに Content-Type
を指定した場合の値の型がサポートされました。ですので、Content-Type
に application/json
というのをフル入力せず「json」と入力するだけで、 application/json
が候補として表示されるようになります。
serveStatic
を使用する際にディレクトリ名にドットを含ディレクトリ名を指定した場合に静的ファイルが返せない場合がある動作の修正
app.get('/favicon.ico', serveStatic({ path: './satic/hello.world' }))
上記のようの例の場合、 hello.world
はファイルなのか、ディレクトリなのかフレームワーク側では現在ファイルとして扱うぽいのですが、実際はディレクトリの場合に hello.world/index.html
を返してほしいが動作しないという振る舞いに対する動作に対応する修正されました。
フレームワーク側ではそれが判断できない場合にディレクトリとして、認識するために isDir
というオプションを渡してディレクトリとして認識させるということが可能になりました。
app.get('/favicon.ico', serveStatic({
path: './satic/hello.world',
isDir: (path) => {
return path === 'static/hello.world'
}
}))
これでディレクトリとして認識されて static/hello.world/index.html
を返してくれるというものになります。
上記の変更で 4.5.5 がリリースされています
4.5.5以降の修正
Uncaught (in promise)
)が発生するとクラッシュする可能性の不具合を修正
非同期コンポーネントでエラー(
PRに書いていますが、クラッシュする条件としては
- 非同期コンポーネントが複数ある
- 最初のPromiseが解決される前に後続のPromiseでエラーが発生する
テストコードをほぼそのまま転載しますが、こんな感じのコードで発生するようです。
const AsyncComponent = async () => {
await new Promise((resolve) => setTimeout(resolve, 10))
return <h1>Hello from async component</h1>
}
const AsyncErrorComponent = async () => {
await new Promise((resolve) => setTimeout(resolve, 0))
throw componentError
}
app.get('/', (c) => {
return c.html(
<>
<AsyncComponent />
<AsyncErrorComponent />
</>
)
})
というものです。非同期コンポーネント自体はReact 19と同様にHonoでも使えるようになったのですが、エラーとなった場合は onError
でハンドリングされないという不具合が修正されました。
4.5.5以降の修正 その2
multipart/form-data
のデータを送信した際にFormDataのvalidationが必ず失敗してしまう不具合の修正
const route = app.post(
'/posts',
zValidator(
'form',
z.object({
body: z.string(),
})
),
(c) => {
const validated = c.req.valid('form')
// ... use your validated data
}
)
HonoではこのようにFormDataのvalidationを行う際に引数に 'form'
という指定をしてvalidationを行うことが出来ますが、 Content-Type
に multipart/form-data
を指定した場合に必ずvalidationが失敗する不具合が修正されました。どうやら原因は Content-Type
のmultipartから始まる正規表現のチェックで空白の指定が誤っているため、Content-Type
が正常でないとみなされて、必ず失敗するといったことが発生したようです。
FormDataの同一キーにappendした際のvalidationを行う値は配列として保持するように修正
要は const form = new FormData()
を行った後に form.append('key', ...)
として同一キーに値を append
していくとそれは配列として扱うのですが、 validation時にFormデータからObjectとして値を復元する際に配列としてみなすように修正されました。(余談ですが、HonoはこのFormDataの配列として扱う修正が多いような気が…)
hono/jsx
metaタグの name
属性に補完が効くように型を追加
これは以前あった c.header
のキーおよび値をある程度、型で補完することができる機能のmetaタグ版です。これによりmetaタグの代表的なものは name
を指定時に補完が効くようになります。
上記の変更で 4.5.6 がリリースされています
4.5.6以降の修正
hono/jsx
にて script
タグが style
タグとして出力される不具合を修正
タイトルのままなんですが、 script
タグを指定しても style
タグとして出力されてしまう不具合が修正されました。
hono/jsx
のレンダリング速度を改善
hono/jsx
と他のライブラリとクライアントでのレンダリング速度を調べてくれた方の報告では、速度の早い順に Solid.js > Preact > React > Hono という順になったようです。それで一番遅いのであれば問題ないのですが、コンポーネント数が多いとブラウザでレンダリングが出来ずハングするようです。
そこで usualoma さんによる速度の改善が行われました。
大きい変更としては「再帰のロジックをやめ、ループで処理するように変更」「Object.definePropertiesの速度が遅いため使用しないよう変更」ということでReact並へのレンダリング速度に修正されました。
a
タグの target
属性に補完が効くように型を追加
以前に書いた c.header
や meta
タグと同様のシリーズの修正です。
a
の target
属性には _blank
などを指定することが出来ますが、これも入力補完が効くように修正されました。
Content-Type
に application/x-www-form-urlencoded
に追加して charset=UTF-8
を指定した場合にvalidationが正しく動作しない不具合修正
「4.5.2以降の修正」で application/json
で同じことがありましたが、 application/x-www-form-urlencoded
でも同様の不具合があり、修正されました。原因は以前と同じ正規表現的に文字コードが入ることがない条件指定となっていたことが原因です。
4.5.6以降の修正 その2
area
タグの target
属性や button
タグの formtarget
に補完が効くように型を追加
「4.5.6以降の修正」で書いた a
タグの target
属性と同じように他のタグでも target
および formtarget
属性の入力に補完が効くように型が修正されました。修正されたタグおよび属性は以下です。
-
area
タグのtarget
属性 -
base
タグのtarget
属性 -
button
タグのformtarget
属性 -
form
タグのformtarget
属性 -
input
タグのformtarget
属性
このシリーズまだまだありそうなのでコントリビュートチャンスではないでしょうか。
x.com
に変更
HonoのXアカウントのURLを
READMEにHonoの公式であるXのアカウントがありますが、そのURLが旧ドメインである twitter.com
であったため、 x.com
に変更されました。
4.5.6以降の修正 その3
hono/client
を使用すると正常なパスで呼び出されない不具合を修正
オプショナルのURLパラメータを定義したルーティングが
HonoではオプショナルのURLパラメータを持ったルーティングを定義することができます。
const app = new Hono()
app.get('/something/:firstId/:secondId/:version?', (c) => c.json({ ok: true }))
上記の例では firstId
および secondId
部分は必須ですが、 version
部分は無くてもこのルーティングに該当するという定義です。つまり /something/1/2
も /something/1/2/3
もこのルーティングで処理されます。
しかし、 hono/client
を使用したRPCを使用して、オプショナルな部分を渡さず呼び出すと呼び出されたURLは /something/1/2/undefined
という風に正常なURLとして渡って来ないという不具合が修正されました。
input
タグの type
および autocomplete
属性について補完が効くように型を修正
最近恒例のシリーズです。今度は input
タグについて type
と autocomplete
属性について入力が補完されるように修正されました。ただ、そこまで詳しく見ていないのですが、 autocomplete
に関してはまだまだ種類は多いようですが、これはあくまでReactと同等の補完ということで承認されています。
上記の変更で 4.5.7 がリリースされています
4.5.7以降の修正
Content-Type
の大文字小文字を考慮しないように修正
CSRF Protection middlewareでチェックする
CSRF対策を行うミドルウェアがありますが、チェック時に Content-Type
の大文字小文字を区別してチェックしていたため、CSRF対策として機能しない不具合が修正されました。
上記の変更で 4.5.8 がリリースされています
4.5.8以降の修正
TypeScript 5.6にした場合にテストが正常に動作しなくなるテストコードの修正
端的に表題の通りなんですが、じゃあなんで次期バージョンの5.6ではこれが通らなくなくなるの?っていうのはちょっと難しい内容です。
そもそもこのテストは型が指定の通りに型となっているかテストを書いています。で、5.6では5.5で発生しているジェネリックによる型評価に不具合があり、それが修正されてリリースされるようです。で、その不具合を対応したTypeScriptのバージョンを使用すると、元々はTypeScriptのバグのせいでテストが通っていたコードが失敗するようになったという経緯です。
4.5.8以降の修正 その2
NO_COLOR
という環境変数へのアクセス権を求められる動作の修正
denoの場合に 標準出力のカラーコード出力の確認ロジックが動作すると
Honoは内部的で標準出力する際に NO_COLOR
の環境変数を見て、標準出力にカラーコードを付与するかどうかの判定を行っているようです。ただ、コードを見るとすべての標準出力がそうではなく、現状は showRoutes
というすべてのルーティングを出力できる開発用の関数があるのですが、その関数で出力する標準出力に NO_COLOR
の環境変数でのカラーコードを出力するかどうかを判定していました。
しかし、Denoの場合は環境変数にアクセスするためには --allow-env
というパーミッションが必要になります。そこでDenoの場合は NO_COLOR
の環境変数を見るのではなく、 Deno.noColor
という --allow-env
パーミッションがなくても NO_COLOR
の環境変数を参照する値を見るように修正されました。
embed
タグや link
の type
属性について補完が効くように型を修正
今度は以下のタグの type
属性について入力が補完されるように修正されました。
- embed
- link
- object
- source
- script
- style
Pretty JSON Middlewareに整形を行うクエリパラメータを指定できるよう修正
Pretty JSON Middlewareを使えば、JSONのレスポンスが整形されたJSON(JSON.stringify({ sample }, null, 2)
)で表示することが出来ましたが、今まではスペースの数値しかオプションで指定できませんでした。なので、Pretty JSON Middlewareを使用すると使用するルーティングは prettye
というクエリパラメータを付与すると整形されるようになっていました。
今回は整形するための特定のクエリパラメータ(デフォルトでは pretty
というパラメータ)を指定することが出来るように変更がされました。オプションなので、以下のように space
と同様に指定することで使用することが出来ます。
app.use(
'*',
prettyJSON({
query: 'format',
})
)
上記の変更で 4.5.9 がリリースされています
4.5.9以降の修正
Compress Middleware
の圧縮を行わないようにする処理の追加
レスポンスBodyを圧縮して返すミドルウェアがありますが、いくつかの条件で圧縮を行わない条件が追加されました。
- エンコード済みの場合
- リクエストメソッドが
HEAD
の場合 -
Content-Length
が1024もしくは指定のサイズ以下の場合 - 圧縮を行わない
Content-Type
(application/jsonやx-www-form-urlencodedなど)の場合 - レスポンスHeadersの
Cache-Control
にno-transform
が付与されている場合
上記の条件のどれかに当てはまるとミドルウェアは圧縮を行わないようにするという処理に修正されました。
popover
属性や popovertargetaction
属性について補完が効くように型を修正
Popover APIの
新しめのAPIに Popover API というものがあるのですが(ざっくり書くとHTMLだけでポップオーバーを表示できるもので、JSでも書ける)、そのAPIを使用するための属性に popover
や popovertargetaction
という属性がありますが、これもある程度決まりのある値を指定します。
それが恒例のシリーズと化していますが、入力を補完するように型が修正されました。
4.5.9以降の修正 その2
button
タグと input
タグの formenctype
属性や formmethod
属性について補完が効くように型を修正
これをほぼ毎日書いてるとコントリビュータの方の名前を見るだけで、次はなんのシリーズと思えるくらいの安心感です。
今回は表題の通り input
タグなどに使用される formenctype
属性や formmethod
属性とその大本の form
タグの enctype
属性と method
に補完が効くように型が修正されました。
また、 form
タグの autocomplete
も一部補完が効くように修正されています。
Vitest をv2へバージョンアップ
Honoで使用されているテストフレームワークのVitestがv2へバージョンアップされました。v2のバージョンアップに伴い一部だけテストが書き換えられていますが、難なく変更されているようです。
4.5.9以降の修正 その3
Vitest v2へのアップデートに伴い deprecated な型の修正
Suite
という型が deprecated になっており、移行先の型である RunnerTestSuite
に修正されました。
logger middlewareで出力されるログの先頭からスペースを削除
logger middlewareを使用する <--
や -->
の先頭にスペース3つが先頭について状態で出力されていました。ただし、ここだけがスペースが挿入されているので他のログを合わせると位置がズレているということなので削除されました。
上記の変更で 4.5.10 がリリースされています
ErrorBoundary
によるエラーをキャッチした場合にクラッシュしてしまう不具合の修正
非同期コンポーネントを複数レンダリングする際に
表題を見てもわからないと思うので、Issueのコードをそのまま記載します。
const app = new Hono();
export const SlowComponent: FC = async () => {
await new Promise((resolve) => setTimeout(resolve, 100));
return <div></div>;
};
const BrokenComponent: FC = async () => {
await new Promise((resolve) => setTimeout(resolve, 10));
throw new Error("Out of service");
};
app.get("/", (ctx) => {
return ctx.html(
<>
<SlowComponent />
<ErrorBoundary fallback="An error occurred">
<BrokenComponent />
</ErrorBoundary>
</>,
);
});
上記の例では BrokenComponent
というコンポーネントはエラーを起こします。しかし ErrorBoundary
が存在するので一見問題なさそうに見えますが、その横にそれよりもレンダリングが遅い SlowComponent
というものが存在します。この場合エラーが起こった後よりもレンダリングを行おうとして処理が正常に行えないということが発生するようです。
この場合でも正常にレンダリング処理が行われるように修正がされました。修正は至ってシンプルで全レンダリングで1つでもエラーがあった場合にエラーを認識するように修正されています。
4.5.10以降の修正
head
タグ内のタグ要素の巻き上げ処理を改善しレンダリング速度を改善
hono/jsx
もReact19同様に title
や meta
タグなどの head
タグに配置するタグをどこに記述しても head
タグに巻き上げる仕様が入っています。しかし、その仕様の動作によりレンダリング速度が遅くなっていたということで、 title
や meta
タグなどが head
タグ内にある場合は処理しないようにして速度が改善されています。
Content-Typeの判定処理にオプショナルチェーンを使用するようにリファクタリング
HonoでBodyをパースする際にContent-Typeが multipart/form-data
か application/x-www-form-urlencoded
の場合にパースするという判定がありますが、その判定にContent-Typeが習得できない場合の判定条件があったので、それをオプショナルチェーンで書くようにリファクタリングされました。
Twitter
という文言を X
という文言に修正
README.md 内に
Twitterのサービス名が変わりましたが、HonoのREADME.mdに一部Twitterというサービス名が残っていたのでXに変更されました。
4.5.10以降の修正 その2
JSX RendererのJSDocへのドキュメントへのURLの指定方法を修正
JSDocにJSX RendererのドキュメントURLが記載されていますが、そのURLの指定方法を正しい記述に修正されました。
Basic認証の認証ロジックを切り出すリファクタリングを実施
Basic認証の認証部分に関する関数が独立して切り出されました。この切り出しには別で提案されているCasbinを使用した認可のミドルウェアを取り込むためのようです。
Casbinはあくまで認可を制御するのであって、認証は別で賄う必要があります。また、認可なので「誰が」というのを把握する必要があり、このリファクタリングでは認証部分で「誰が」というのを習得しやすくするためにリファクタリングが行われたという背景がありそうです。
上記の変更で 4.5.11 がリリースされています
4.5.11以降の修正
JSX Renderer MiddlewareのJSDoc内の名称を正しい名称に変更
"JSX" Renderer Middlewareですが、"JSR"と記載されているJSDocがあり、"JSX"という正しいJSDocドキュメントに修正されました。
@std/assert
をJSRから取得して使用するように修正
Denoのテストに使用する
Denoのランタイムで行うテストコードでassetを行うライブラリがJSRから取得して使用するように修正されました。
これにはどうやら背景があるようで、Denoにて先日リリースされたCache APIをサポートするための機能を開発のようですが、キャッシュの有効期限をHono側で制御するための処理が組み込まれる(Denoのキャッシュにはexpireを設定できないぽい?)ようで、その過程でテストライブラリを更新する必要があるようです。
4.5.11以降の修正 その2
ここからはリリースされた 4.6.0 および 4.6.1 の内容のコミットの説明になっていきます。
Permissions-Policy
ヘッダーを設定できるように修正
Secure Headers Middlewareに
HTTPのヘッダーに Permissions-Policy
ヘッダーというものを設定することでブラウザからWebページにアクセスできる機能を絞ることが出来ます。例えば camera
geolocation
microphone
といったアクセスを制御することでXSS攻撃などのリスクを低減することが出来ます。
この変更によりSecure Headers Middlewareでは Permissions-Policy
が設定出来るようになりました。
const app = new Hono()
app.use(
'*',
secureHeaders({
permissionsPolicy: {
fullscreen: ['self'], // fullscreen=(self)
bluetooth: ['none'], // bluetooth=(none)
payment: ['self', 'https://example.com'], // payment=(self "https://example.com")
syncXhr: [], // sync-xhr=()
camera: false, // camera=none
microphone: true, // microphone=*
geolocation: ['*'], // geolocation=*
usb: ['self', 'https://a.example.com', 'https://b.example.com'], // usb=(self "https://a.example.com" "https://b.example.com")
accelerometer: ['https://*.example.com'], // accelerometer=("https://*.example.com")
gyroscope: ['src'], // gyroscope=(src)
magnetometer: [
'https://a.example.com',
'https://b.example.com',
], // magnetometer=("https://a.example.com" "https://b.example.com")
},
})
)
Honoのドキュメントのまんまですが、詳しくはこちらを参照ください。
_middleware.ts
でHonoを使用した際にContextが正常に動作するように修正
Cloudflare Pages Functionsの
ちょっとマニアックなのですが、Cloudflare Pages Functionsにはmiddleware用のファイルを置いてmiddlewareを定義することが出来ます。
そのmiddlewareのファイル( _middleware.ts
)で hono/cloudflare-pages
を使用してContextに設定しても本体側でContextを取得するコードを書いても undefined
になります。(それはそうなんですが)
// functions/_middleware.ts
import { handleMiddleware } from "hono/cloudflare-pages";
export const onRequest = [
handleMiddleware(async (c, next) => {
console.log("middleware setting user");
c.set('user', 'joe')
await next();
})
]
// functions/api/[[route]].ts
import { Hono } from "hono";
import { handle } from "hono/cloudflare-pages";
interface HonoContext {
Variables: {
user: string
};
}
const app = new Hono<HonoContext>().basePath('/api');
const routes = app.get('/hello', (c) => {
return c.json({
message: `Hello, ${c.get('user')}!`
});
});
export const onRequest = handle(routes);
で、この修正はまさにCloudflareの中の人って感じの修正なのですが、 functions/_middleware.ts
から 本体のプログラム( functions/[[route]].ts
)に渡すためのInterfaceがあるようです。(ドキュメントには明確に触れられていないですが)
そこで、そのInterfaceを使って渡せるようになったというのがこの修正です。(これはかなりマニアックな修正です)
// functions/_middleware.ts
import { handleMiddleware } from 'hono/cloudflare-pages'
export const onRequest = [
handleMiddleware(async (c, next) => {
c.env.eventContext.data.user = 'Joe'
await next()
}),
]
// functions/api/[[route]].ts
import { Hono } from 'hono'
import type { EventContext } from 'hono/cloudflare-pages'
import { handle } from 'hono/cloudflare-pages'
type Env = {
Bindings: {
eventContext: EventContext
}
}
const app = new Hono<Env>().basePath('/api')
const routes = app.get('/hello', (c) => {
return c.json({
message: `Hello, ${c.env.eventContext.data.user}!`, // 'Joe'
})
})
export const onRequest = handle(routes)
raw
の型をジェネリックで生成するように修正
WebSocket Helperで
WebSocket Helperで raw
を使用する際は以下のようなコードになりますが、そもそも raw
が unkown
の型になっていますので、基本的には自分でキャストするか型エラーを無視するしかありませでした。
app.get(
'/ws',
upgradeWebSocket((c) => {
return {
onMessage(event, ws) {
// @ts-expect-error
ws.raw.subscribe('chat-test')
},
}
})
)
それがこの修正でジェネリックとなったため raw
にも自動的に型が入り、例えばBunならば ServerWebSocket
とという型が入って使用することが出来ます。
Content-Encoding
ヘッダーに Identity
が設定されるように修正
JSXのレンダリングにて steam の場合は
内容からすべてを把握出来るわけではないですが、どうやら Suspense
の処理でエンコードされていないことを明示的に渡しておく必要のあるための修正のようです。
Context Storage Middlewareの追加
今までHonoはContextにアクセスするにはハンドラーから受け取ったContextを各処理に伝搬していく必要がありましたが、このContext Storage Middlewareを使用するとハンドラー外からの処理でもContextにアクセス( getContext
)することが可能になります。
これは AsyncLocalStorage
というグローバルに値を格納できるAPIを用いて実装されており、そこに格納されたコンテキストを取得するという処理になっています。
静的ファイルを返却する際に事前に圧縮済みファイルがある場合はそれを返却するできるように修正
例えばJavaScriptにhttpでリクエストした際にJavaScriptファイルを返すのではなく、事前に対応されたgzipファイルを返すということがこの修正で可能になりました。これはNginxなどにも機能として存在しますが、Honoでこれをサポートするということになりました。使用するには precompressed
というオプションに true
を渡すと使用することが出来ます。
import { serveStatic } from '@hono/node-server/serve-static'
app.use('/static/*', serveStatic({ root: './', precompressed: true }))
streamSSE
で 非同期コンポーネントの返却できるように修正
Server Send EventではStreamを出力できるように修正されました。以前に似たようなPRが作成されたようですが、今回はSSEで renderToReadbleStream
が使えないということで修正されたようです。
fetch
で取得したResposeをそのまま返すとエラーになる場合がある不具合の修正
どうやら fetch
で取得したResponseをそのまま返すとエラーになる場合があるようです。原因はどうやら取得したResponseをmiddlewareなどでHeadersを変更しようする処理でうまく変更できずにエラーとなるようなので、それが修正されました。
Permissions-Policy
ヘッダーに設定できるディレクティブを追加
Secure Headers Middlewareに
Permissions-Policy
ヘッダーに設定できるディレクティブに usb
や accelerometer
gyroscope
magnetometer
を設定できるように修正されました。
serve-static にファイルが見つかった際のコールバックハンドラーの処理を追加
静的ファイルを配信する際に特定のファイルの配信する際にResponseヘッダーを書き換えたいなどの要望に応えるために onFound
というコールバックハンドラーを指定することで処理ができるようにオプションが追加されました。
app.use('/static/*', serveStatic({
root: './',
onFound: (path, c) => {
if (path.endsWith('hoge.jpeg')) {
c.header('Cache-Control', `public, immutable, max-age=31536000`)
}
},
}
Basic認証にて認証に失敗した際のBodyメッセージをカスタマイズできるオプションを追加
今まではBasic認証で認証エラーとなった場合は 「Unauthorized」 というメッセージ(Body)が固定が返っていましたが、それを指定できるようにするオプションが追加されました。
const app = new Hono()
app.use(
'/auth/*',
basicAuth({
username: 'hono',
password: 'acoolproject',
invalidUserMessage: () => 'Custom unauthorized message as function string'
})
)
invalidUserMessage
オプションには文字列や関数および message
プロパティを持ったオブジェクトを指定することが出来ます。
Bearer認証にもBasic認証同様に認証に失敗した際のBodyメッセージをカスタマイズできるオプションを追加
上記で説明した認証エラー時のメッセージをBearer認証を行うBearer Auth Middlewareにも同様に修正されました。
認証エラーに失敗した際のカスタムメッセージを設定するオプション名のTypoを修正
invalidAuthenticationHeaderMeasage
から invalidAuthenticationHeaderMessage
にTypoが修正されました。
上記の変更で 4.6.0 がリリースされています
//
と連続するスラッシュがパスとして出力されないように修正
ビルドしたファイルの参照パスが
Honoのビルドをする設定にものによればファイルパスを結合する処理で //
とスラッシュが2つ続いてファイルを参照するコードが生成されてしまうことがあるようです。これはランタイム(報告ではDeno。というかDenoの中の人)によっては不具合を起こしてしまうようで、 //
とならないように正常にファイルパスを出力するビルド処理となるように修正されました。
上記の変更で 4.6.1 がリリースされています
4.6.1以降の修正
ESLint v9にアップデートおよびflat configに対応
Hono自体の処理に変更は無いようです。あくまでESLint v9およびflat configに対応したようです。ESLint v9にアップデートと同時に eslint-plugin-import-x
から sort-imports
に変更したようです。
4.6.1以降の修正 その2
事前に圧縮済み静的ファイルを返す場合のパフォーマンスを改善
具体的には以下の変更により処理を早くしたようです。
- Requestの
Accept-Encoding
から検索する圧縮ファイル種類のロジックを最適化 - Responseが圧縮可能な
Content-Type
以外は圧縮ファイルを検索しない -
Content-Type
は圧縮ファイルが見つかった場合にのみ設定する
という処理の変更を加えて少しでも速度の改善を行ったようです。
4.6.1以降の修正 その3
Content-Type
に application/octet-stream
を設定するように修正
事前圧縮済みの静的ファイルの拡張子からMimeTypeが取得出来ない場合は
昨日の事前圧縮ファイルを配信するためのパフォーマンス改善の処理の変更により Content-Type
は圧縮ファイルが存在した場合に設定するように変更されました。また、見つかっても拡張子から判断出来ない場合は Content-Type
が text/plain
が設定されていました。しかし、バイナリファイルの可能性があるため Content-Type
が適切ではないとして拡張子で判断出来ない場合は 'application/octet-stream
を設定するように修正されました。
上記の変更で 4.6.2 がリリースされています
ランタイムに依存するテストコードのディレクトリ名のアンダーバーをハイフンにリネーム
Honoのリポジトリでは、ハイフンを用いたファイル名やディレクトリ名で設定されているようですが、ランタイムに依存するディレクトリ名だけがアンダーバーが使用されており、他と統一するためにハイフンに変更されました。
4.6.2以降の修正
型チェックを行う場合のパフォーマンスを計測するように修正
以前 RPCを使用する場合に返るJSONの型を変更した修正がありましたが、その際にパフォーマンスが低下してしまうという問題が一時発生してしまいました。そこでPRの段階でパフォーマンスの低下が起きていないかチェックを行うCIが導入されました。
4.6.2以降の修正 その2
await
の記述を削除して、 renderToReadableStream
の型を修正
不要な
renderToReadableStream
に不必要な await
が定義されていましが、それが不要になるようにコードがリファクタリングされました。これによりコードを読む際の混乱がなくなるようになりました。
ハンドラーのパスからの型生成のパフォーマンスを10%改善する修正
Honoではパスからパラメータなどの型が生成する処理がありますが、その型を生成する処理の速度が改善する修正が行われました。これは前回記載した型チェックのパフォーマンス計測より変更後のコードを適用すると測定した結果では10%程度早くなるようです。
同水準の型を纏めて型の分岐を抑えるように修正
RPCなどのJSONを返す場合の型の返り値を分岐している箇所にて何通りか存在しますが、ほぼ同じ型については分岐せず1つに纏めて型定義をするように修正されました。
型チェックのパフォーマンスの計測結果の出力結果のテーブルフォーマットを調整
型チェックのパフォーマンス結果はテーブルフォーマットで出力されますが、その出力を微調整して見やすくするように修正されました。
useSyncExternalStore
の第一引数のsubscribe関数の型を正しい型に修正
HonoもReact互換なので useSyncExternalStore
が存在します。 useSyncExternalStore
の第一引数はsubscribeとなる関数を指定しますが、これは引数なしの関数を指定する必要があり、引数が存在する型となっていたので、引数を持たない関数の型に修正されました。型の修正のみであり、実動作に変更ありません。
4.6.2以降の修正 その3
every
関数にてReponseを返すと以降のmiddlewareは実行されないように修正
Combine Middlewareの
Combine Middlewareには every
という関数がありますが、これは複数のmiddlewareをすべて実行して1つでも失敗したらハンドラーを実行しないというものですが、この every
に指定したmiddlewareで1つでもReponse相当(c.text
など)を返すと指定されたResponseをmiddlewareから返すという風に変更されました。
これによりエラーのReponseだけでなく独自のReponseを返すことが可能になります。
Content-Security-Policy-Report-Only
をサポートするように修正
Secure Headers Middlewareにて
Secure Headers Middlewareで Content-Security-Policy
はサポートされていましたが、 Content-Security-Policy-Report-Only
はサポートされていませんでしたが、この変更によりサポートされるようになりました、。
JwtVariables
型をジェネリックで指定できるように修正
JWT Auth Middlewareの
JWT Auth Middlewareの JwtVariables
は固定で以下の型でした。
export type JwtVariables = {
jwtPayload: any
}
なので内部の jwtPayload
は常にanyでしたが、 jwtPayload
の型をジェネリックで指定できるように修正されました。
HonoRequest
をインスタンス化できるように exports
の設定を追加
Honoを使用したフレームワークに Danet
というものがあるらしいのですが、そのフレームワークでHonoを使用するためにHonoでRequestオブジェクトを扱うための HonoRequest
を独自にインスタンス化して使用するためアクセスできる必要があるという要望のために exports
の設定が追加されました。これはJSRに移行する前のHonoでは出来たことらしいですが、JSRに移行したと同時に HonoRequest
がインスタンス化できなくなったということで修正が認められたようです。
precompile
を指定した場合に属性値が正常に出力されない不具合修正
JSXにて
HonoのJSXはDenoで動作させるためには precompile
という設定を行う必要があるのですが、この設定を行うと属性値が文字列で正常に出力されず [object Object]
で出力されてしまう不具合が修正されました。
serveStatic
にて絶対パスをサポートするように修正
serveStatic
にて スラッシュから始まるパスを指定することで絶対パスとして認識するように修正されました。
上記の変更で 4.6.3 がリリースされています
devDependencies
にて使用するパッケージのバージョンを指定を修正
Honoが開発で使用するパッケージのバージョンが以下のように修正されました。
-
@hono/eslint-config
を1.0.2にアップデート -
wrangler
を3.58.0に固定
wrangler
のバージョンを固定した糸がちょっとわからないです。
crypto-js
を devDependencies
から削除
テストコード内でSHA256を生成してテストしているコードがありますが、SHA256は crypto
APIを使用して生成できるために crypto-js
で生成する必要がないということで変更されたと同時に crypto-js
は使用されなくなったので削除されました。
4.6.3以降の修正
変数として宣言されているが、型としか使用していないESLintの警告を無効化するように修正
テストコードの中にはHonoをインスタンス化してテストとして使用していますが、インスタンス化したオブジェクトを変数に入れて型としか使用していないものが存在します。テストコードとしては仕方ないのですが、ESLintの警告が常に出続けるため、PRを出した場合にCIが動いた結果にノイズとして出力されていました。
そこでノイズになるので、その警告を出力しないように該当ファイルはESLintのルールを一部無効化する修正がされました。
4.6.3以降の修正 その2
Bunもカバレッジを計測するように修正
Bunがlcovによるカバレッジの計測に対応したことによりHonoでのテストのカバレッジ計測でBunも計測されるように修正されました。
4.6.3以降の修正 その3
denoのmiddlewareのテストで不要なルーティングを削除
middlewareのテストで同一のルーティングが2重に登録してしまっているテスト用のHonoアプリケーションから不要なルーティングが削除されました。
4.6.3以降の修正 その4
hono/jsx
でもカスタムコンポーネントにkeyを設定できるように修正
Reactではどんなコンポーネントでも key
のPropsを定義することが出来ますが、 hono/jsx
ではカスタムコンポーネントに key
を指定すると型エラーが発生するようです。なので key
を渡しても型エラーが発生しないように修正されました。
function RenderCustomComponent() {
return <RenderDivComponent key={"key"} value={1} /> // type error: Property 'key' does not exist on type '{ value: number; }'
}
function RenderDivComponent({ value }:{ value: number }) {
return <div key='div'>{value}</div> // no type error
}
4.6.3以降の修正 その5
createMiddleware
のジェネリックに指定する型が異なる2つのミドルウェア関数にContextを渡すと型エラーになる不具合修正
自分でもどうタイトルを書くとわかりなすか悩ましいです。
コードを見るのが早いと思います。
const middlewareOne = (_variable: string) =>
createMiddleware<{ Variables: Variables }>(async (c, next) => {
await next()
})
const middlewareTwo = createMiddleware<{ Bindings: Bindings }>(async (c, next) => {
const mw = middlewareOne(c.env.MY_VAR_IN_BINDINGS)
await mw(c, next) // type error
})
このように createMiddleware
で生成するミドルウェアの関数でジェネリックに指定する型が異なる場合にミドルウェアの関数からもう1方のミドルウェアを呼び出す際にコンテキストを指定すると型エラーとなる不具合が修正されました。
Service Worker Adapterを使用してルーティングが存在しないURLにアクセスするとエラーが発生する不具合の修正をさらに修正
「4.5.2以降の修正 その2」でservice worker adapterでの不具合に触れましたが、 globalThis
からの fetch
を正しく取得する方法についてさらに修正されました。
hono/jsx
の toStringToBuffer
関数が deno の環境下のテストでエラーが出ないようにリファクタリング
Denoの環境下のテストで toStringToBuffer
のエラーが出るようなので override
を付与してテスト時にエラーとならないようにリファクタリングされました。
上記の変更で 4.6.4 がリリースされています
app.route
の型評価の速度を改善
Honoで app.route
という2つの route を結合するような関数が存在しますが、それを使用した場合のハンドラー関数への型評価速度が改善するように修正されました。
4.6.4以降の修正
denoのCI環境でv2を使用するように変更
CIの環境下のdenoのバージョンが1だったものが2に変更されました。
4.6.4以降の修正 その2
denoのCI環境でv1を使用が残っていたためv2に変更
昨日、CIでdenoをv2環境で動作させる修正を行いましたが、まだv1で動作しているCI環境があったため、v2に変更されました。
4.6.4以降の修正 その3
ExcludeEmptyObject
という型を削除
Honoの内部で使用される
ExcludeEmptyObject
というのはいわゆるカラのオブジェクトなのですが、これを別の定義場所に持っていこうとすると Type instantiation is excessively deep and possibly infinite.
というエラーが発生するようです。なので使用しなくてもいいように型が修正されました。
Access-Control-Allow-Origin
を設定しないように修正
CORS Middlewareで設定したOriginと一致しない場合は Response Headersに
CORS MiddlewareでOriginを設定することが出来ますが、設定したOriginとリクエスト元のOriginが一致しない場合でも Access-Control-Allow-Origin
が設定されてレスポンスを返していたようです。なので一致しない場合は Access-Control-Allow-Origin
を設定せず厳格にレスポンスを返すという修正がされました。
4.6.4以降の修正 その4
'X-Powered-By
を指定できるように修正
Powerd By middlewareを使用して
X-Powerd-By
は Hono
固定でしたが、このミドルウェアを使用して、Server名を指定することでカスタムのServer名を設定できるオプションが追加されました。
createMiddleware
のジェネリックに指定する型が異なる2つのミドルウェア関数にContextを渡すと型エラーになる不具合修正」の変更を元に戻す
「
「4.6.3以降の修正 その3」で書いた修正がリバートされました。リバートした理由としては c.get
が正常に型が設定されないという不具合を招いてしまったようです。そこで前回の問題の修正を行うためにはすぐに対応方法がないため、リバートされたようです。
Content-Type
が未指定の場合は text/plain
としてみなすように修正
CSRF ProtectionにてRequest Headerの
CSRFのチェックにてRequest Headerをチェックしますが、 Content-Type
が未指定のRequestについては text/plain
としてみなして動作するように変更されました。なので未指定の場合は基本的にはエラーとなるはずです。
#private
の型エラーが発生しないようする修正
異なるバージョンのHonoを2つ以上プロジェクト内に配置すると
詳しくは見てませんが、Honoを異なる2つのバージョンをインストールした場合に型の参照がおかしくなるようです。そこでビルド後に出力される型ファイルからprivateな型は削除してエラーが発生しないようにする対応がされました。
bun.lockb
を更新
理由はわかりませんが、lockファイルの更新が行われました。何かバージョンの差異が出ていたのでそうか。
上記の変更で 4.6.5 がリリースされています
Powerd By middlewareのJSDocの追加
Powerd By middlewareについてのJSDocが追加されました。現状Powerd By middlewareに関するドキュメントは公式のサイトにはないので後に追加するようのでしょうか。
4.6.5以降の修正
HonoをVS Codeのdevcontainerで使用する際にpodmanで動作するように修正
Honoの開発環境はVS Codeのdevcontainerで動作する設定が存在します。この設定をdockerではなく、podmanでも動作するように修正されました。
4.6.5以降の修正 その2
nonce
値を生成するロジックを読みやすいようにリファクタリング
Secure Headers Middlewareの
Secure Headers Middlewareで設定する nonce
は c.get('secureHeadersNonce')
で取得できますが、ミドルウェアで c.set('secureHeadersNonce', value)
をする際の value
の値の決定ロジックが内部関数を生成して実行しているため少し読みにくいのか、リファクタリングが提案されてマージされました。
serveStatic
を使用した場合に配信ファイルが見つからない場合は警告表示を非表示にする
Denoで
Denoではファイルの存在確認が行えないので、存在しないファイルを取得しようとすると必ず例外となるようです。そのため存在しないファイルへのアクセスをするとcatch節に入り、warningのログを必ず出力してしまうようです。そこでファイルが存在しない例外以外の場合だけwarningのログを出力するようにするという変更がされました。
$url
にクエリパラメータを指定した場合にクエリパラメータが付与されたURLで返ってくるように修正
RPCの
HonoのRPCには $url
というメソッドが使用でき、エンドポイントへのURLオブジェクトを返すメソッドがあります。この $url
にクエリパラメータを付与しても返ってくるURLオブジェクトにはクエリパラメータ(SearchParams)が無い状態で返ってきていたので、クエリパラメータを含めたURLオブジェクトが返ってくるように修正されました。
上記の変更で 4.6.6 がリリースされています
4.6.6以降の修正
Vercel Adapterのハンドラー関数をNext.js 15で使用できるハンドラーに変更
Next.js 15ではルートハンドラーを定義する際の第2引数はオプショナルとなりました。また、第2引数で指定したとしてもURLパラメータが取得できるだけなので、Honoでは c.req.param()
で取得できるため、第2引数は指定しないハンドラー固定を提供するように修正されました。
JWTの認証処理にカスタムSecret Keyで署名されたJWTも認証できるように修正
タイトルの通りそのままなのですが、JWTには署名する際に secret ととなる文字列を指定することができますが、これを指定したJWTの認証処理が行えるように修正されました。
4.6.6以降の修正 その2
カスタムWebSocket Adapterを作成しやすいように接続するためのAPIとなるインターフェースを変更
WebSocketを接続するためにあるヘルパーの UpgradeWebSocket
を使用して、独自のAdapterを構築した際に、 UpgradeWebSocket
のインターフェースが変更されてしまうとカスタムAdapter側もHonoの変更に追従する必要があります。そこで、ヘルパーのAPIが変更となってもカスタムAdapter側で変更が少なくなるようにWebSocket接続のためのインターフェースとなるAPIが一部変更となりました。
使用感としては今まで通りですが、WebSocketを使った独自Adapterを実装した場合のインターフェースが変更に耐えれるように修正されたくらいだと認識して大丈夫です。
4.6.6以降の修正 その3
ルーティングの速度を改善
コードを読む限り内部的な変更ですが、以下のような修正を行ったようです。
-
for of
からfor
にループを変更して速度を改善 - ルーティング判定用の内部ルーティング名を削除して、一致したハンドラーは一致フラグ(ループインデックス)から取得
一部IF文のリファクタリングも行われて、可読性を向上させたとありますが、元は早期リターンで書いていたのがIFがネストする形になっているのはいいのだろうかとは思いますが、Honoを使用するユーザ的には「変数が減ってメモリが微小だが軽く」なり「for-of
から for
に変更して判定速度が微小だが向上」くらいの内容だと思って大丈夫だと思います。
上記の変更で 4.6.7 がリリースされています
4.6.7以降の修正
BunでWebSocketのハンドラーの型を正しい型に修正
Bunを使用して、WebSocketを使用する場合に以下のコードで websocket
のハンドラー部分で型エラーが発生してしまっていたようです。原因はWebSocketで処理するメッセージの型が誤っていたようです。型のエラーだけなので型エラーさえ無視してしまえば動作には問題ないようです。
import type { ServerWebSocket } from 'bun'
import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'
const { upgradeWebSocket, websocket } = createBunWebSocket<ServerWebSocket>()
const app = new Hono()
Bun.serve({
port: 4000,
fetch: app.fetch,
websocket, // type error
})
Cookieのパーテイション分割の属性名を正しい属性名に変更
Cookieにはパーティション分割を行う属性名( partitioned
)を設定することができますが、Honoから設定しようとすると誤った属性名で型定義されているため、正しい名称で設定しようとすると型エラーが出るそうです。なので正しい属性名の partitioned
で設定できるように型定義が修正されました。
4.6.7以降の修正 その2
WebSocket接続のコンテキストクラス名のTypoを修正
「4.6.6以降の修正 その2」で触れましたがWebSocketを使った独自Adapterを構築する際にAPIの変更に耐えれるようにということを書きましたが、それがコンテキスト(Context)というクラスでインターフェースが定義されましたが、Context
ではなく、 Contest
とTypoされていたクラス名などが修正されました。
WebSocketでストリーミングデータを送信する際にバッファ全体を返してしまう場合がある不具合の修正
具体的には Uint8Array
の場合にはバッファ全体を送信する場合にバッファ全体を返すという処理になっていました。そうするとストリーミングで Unit8Array
のデータをクライアントに返す際にバッファ全体を送ってしまうので、不要な帯域データを流すことになってしまうということです。
ですので、 Unit8Array
でも問題なくストリーミングで送信できるようにそのままデータを送信するという風に変更されました。
Bunでホットリロードした際にWebSocket接続でエラーが起きないように修正
Bunを使用して開発する際に --hot
というオプションを付与して起動するとホットリロードするようになるようです。そこでWebSocketを使ったアプリケーションを構築しているとサーバ側はファイルを再読み込みしますが、クライアントからはWebSocketの接続が失われ再接続がされますが、サーバ側は接続情報をグローバルに持っており、古い接続が切れたことを認識できずに古い接続先に対して処理をしようとしてエラーとなるというのが原因だそうです。
なので、接続情報はHono側で覚えるのではなく、Bunが接続しているWebSocket接続に対して処理をするという方法に変更されました。
Request Headerから値を取得する場合のキーに補完されるように型を修正
今まではResponse Headerの設定時に型による補完が効いていましたが、今回はRequest Headerの値を取得する際にキーを指定する c.req.header('<key name>')
のキー名に対して補完が効くように型が修正されました。
docker compose
の設定から不要な設定を削除
Hono開発用の
Honoでは開発環境がすぐに用意できるようにリポジトリにVSCodeのdevcontainerの設定が入っています。その設定の中でPodman対応時に入ってしまった不要な設定(ルートレスの場合の設定)が削除されました。
仮にルートレスでPodmanを使用している方がいればこれが必要かもしれませんが、現状は不要ということで削除されました。
Hono内部の型が循環参照になっているのを修正
Hono内部にはいくつかの型定義があるのですが、型ファイルの参照が循環参照になっているということでそうならないように修正されました。
上記の変更で 4.6.8 がリリースされています
4.6.8以降の修正
様々なTypoを修正
基本的に「テスト内容(it, test, describe)」や「変数名」を中心に多岐にわたるタイポが修正されました。
パスパラメータに無効はURLエンコード文字列があった場合は、無効な文字をそのまま使用するように修正
例えば以下のようなルーティングを作成します。
const app = new Hono()
app.get('/test/:path', (c) => {
retrun c.text(c.req.param('path'))
})
Honoでは :path
部分がダイナミックなURLとして認識されますが、2バイト文字やその他URLに含めれない文字はURLエンコードするとURLとして使えますが、そのURLエンコードが正しくエンコードされてなく、デコード出来ない場合にはそのままの文字を返すという修正が行われました。
以前はデコード出来ない場合はエラーをスローしており、最悪はアプリケーションが停止するという外部からの攻撃をうける可能性があるということでこのように変更されました。
hono/jsx
のメモ化の実装方法を変更
ちょっとコード的には難しいのですが、今まではレンダリングした結果をメモリ上に保持し、それをもってメモ化つまりは前回と同一かどうかのチェックを行っていましたが、この変更によりレンダリングする際にそもそも再評価する対象化どうかを新旧のPropsで判断するという手法に変更されました。
フラグメントが連続するJSXが正しくレンダリング出来るように修正
以下のような連続するフラグメントがあった場合に今までは正しくレンダリング出来なかったようなのですが、それが正しくレンダリングされるように修正されました。
const componentChild = () => {
return (
<>
<div>
test child
</div>
</>
)
}
const componentParent = () => {
return (
<>
<componentChild />{/* “Fragment is continuous across components */}
<div>
test parent
</div>
</>
)
}
判定処理を都度行うのではなく、使い回すように修正
Honoには compose
という複数のmiddlewareなどを実行を制御している処理があるのですが、その中である引数で渡ってきた値が、 instanceof
で特定のものと同一かチェックを行っているのですが、その instanceof
の判定を最初に変数にセットして後の処理はその変数の値を使い回すという風にコードが変更されました。
リファクタリングに近い感じのコードですが、Node.jsでは若干のパフォーマンス改善となったため、マージされたようです。
.concat
を使用してパフォーマンスを改善
配列のマージ処理にスプレッド構文を使用せず
2つの配列を1つの配列にマージするコードとして以下のようにスプレッド構文を使用する方法から .concat
を使用するコードに変更されました。
const arrayA = ['A', 'B', 'C']
const arrayB = ['a', 'b', 'c']
// use spread syntax
console.log([...arrayA, ...arrayB])
// use `concat`
console.log(arrayA.concat(arrayB))
このように2つの配列を結合するような処理ではスプレッド構文を使用するよりも .concat
を使用した方が処理速度に軍配があがるようです。
any
を削除するように型定義を修正
deno adapterの処理内に使用されている一部の
DenoのAdapter内に静的ファイルを返す処理があり、そこで一部型定義に any
が使用されているので any
を使用しないように型定義が修正されました。
4.6.8以降の修正 その2
無駄なスプレッド構文の展開処理などをリファクタリング
大きくは固定オブジェクトにプロパティを追加する際に、元のオブジェクトをわざわざスプレッド構文で展開するというコードなどがリファクタリングされました。
関数を他にある代替の関数に変更することで参照されなくなった元の関数を削除
元々あった存在した関数A(仮称)の中身は他の関数B(仮称)を呼ぶ関数だったため、その関数Aを削除して、関数Aを呼んでいた箇所は直接関数Bを呼ぶという風にコードが変更されました。
変更することにより元々の関数Aは参照されなくなり、コードを削除することでHono自体のバンドルサイズも気持ちですが小さくなるというリファクタリングがされました。
indexOf
を使用することで処理を高速化
文字列検索に正規表現ではなく、
URLの中に %
の文字(URLパラメータのチェック処理とだと思われます)が入っているかどうかのチェックに正規表現である /%/.test
が使われていましたが、固定文字を検索するだけであれば indexOf
の方が高速ということで indexOf
を使った判定に修正されました。
entries
でKey/Valueでループする処理を for
に書き換えて高速化
オブジェクトを
これはちょっと面白いなと思ったのですが、具体的には以下のようなコードです。
const target = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
}
Object.entries(target).forEach(([key, value]) => {
console.log(`key: ${key}, value: ${value}`))
}
という風にキーと値をセットでループしたい時によく書くコードですが、これは以下のような for
で書いた方が処理が早いようです。勉強になりました。
for (let i = 0, keys = Object.keys(target), len = keys.length; i < len; i++) {
const key = keys[i]
console.log(`key: ${key}, value: ${target[key]}`)
}
4.6.8以降の修正 その3
Array.isArray
を使用するように修正
配列判定を
修正理由はちょっと細かいようですが、ESLintではデフォルトで instanceOf
を使うより Array.isArray
を使うようにというルールがあるようです。また、コードのバイト数的にも Array.isArray
の方が短いということで修正されたようです。
undefined
を typeof
を使用しない評価式に変更
undefined
を評価する方法としてJavaScript(TypeScript)はいくつかありますが、Hono内部で一部 typeof
で取得したものから文字列で undefined
と一致するかどうかという評価式の記述が、変数自体が、 undefined
と等価かどうかの評価式に変更されました。
JavaScriptって怖いのは undefined
という変数を作ってそこに値を入れれます。それを評価式に使うと…(笑)
無駄なスプレッド構文を削除してコードを読みやすく変更
このコミットは何パターンかのスプレッド構文を読みやすくしているのですが、例えば以下のような無駄なスプレッド構文の変更などがされています。
const hoge = { fuga: 'fuga' }
const other = { test: 'value' }
-{
- ...{
- hoge,
- ...other
- }
-}
+{
+ hoge,
+ ...other
+}
for
ループに書き換えた速度改善コードを一部 for-of
に戻す
昨日の for
への繰り返し処理のコード変更から配列自体がそこまで大きくないと for-of
もそこまで遅くないのと、コードの可読性から読みやすい for-of
に戻したようです。
c.redirect
の引数に URL
を渡せるように修正
リダイレクトの処理には c.redirect
の引数に文字列でURLを指定する必要がありましたが、URLオブジェクトそのものを渡せるようにするという変更がされました。これにより文字URLオブジェクトわざわざ文字列に変換せずとも渡せるようになりました。
4.6.8以降の修正 その4
CIでBunおよびDenoの最新バージョンを使用するように修正
Denoは何回かCIのバージョン修正が行われていますが、まだ少し残っていたようです。Bunに関しては使用するGitHub Actionsのバージョンをv2にアップデートしつつ、Bunの最新バージョン(今日 1.1.34
がリリースされてますが)である 1.1.33
にアップデートされました。
Issue Templateに可能であればランタイムのバージョンも記載してもらうように修正
1つのランタイムでもバージョンごとに動作が異なる可能性も無いので、バージョンを記載してもらい報告内容の再現を用意にしたい目的だと思います。
Logger Middlewareの出力ログのカラーを最適化
今まではhttpステータスで以下のカラー表示でした。
- 700番台 : マゼンタ(ピンクぽい色)
- 500番台:赤
- 400番台:黄
- 300番台:シアン(水色ぽい色)
- 200番台:緑
- 100番台:緑
- 100未満:黄色
- 上記以外は白
それが以下のように変更されました。
- 500番台:赤
- 400番台:黄
- 300番台:シアン(水色ぽい色)
- 200番台:緑
- 上記以外は白
700番台はそもそも出力できないので削除していいとは思うんですが、100番台ってWebSocketのステータスで使うような気がして、そこは削除しないくてもよかったのかなとか見てて思ったりしました。
重複しているMimeTypeの型定義を1つに定義するように修正
微妙に書き方が異なる2つのMimeTypeの型があったのを1つに纏めて定義するように型定義が修正されました。
4.6.8以降の修正 その5
バグでないIssue報告は自動的にCloseするcronジョブを作成
Issue報告で not bug
のラベルが付与されたIssueは最短で9日後に自動的にCloseされるCIのジョブが作成されました。これにより報告後に放置されたIssueが自動的に削除されるようになります。
Math.floor
をビット論理和に変更して速度を改善
ハックぽいコードですが、整数以下を切り捨てる Math.floor
の関数がありますが、ビット論理和を使用して同等のことをして速度を改善するというコードに一部変更されました。
console.log(Math.floor(560 / 100))
console.log(560 / 100 | 0)
この2つのコードは結果的には 5
を出力し、同値になります。ただし、これは 正数値ではという条件になりますので、使用には注意が必要です。
Cookieのパース処理でNameが指定されている場合のデータ返却を高速化
単純なロジックの変更ですが、今まではCookie全体をパースしてからNameが指定されている場合は指定のNameに対応したCookieを返すという処理でしたが、Cookieをパースしていく過程で指定のNameのものが見つかった場合は即座に返すという処理に変更されました。
Privateな関数名がMinifyされた場合にMinifyされるようにリファクタリング
ESBuildでは class
定義でprivateな関数を定義してビルドした際は関数名がそのまま出力されてMinifyされないようです(知らなかった)そこで、privateな関数はMinifyされてHonoサイズを小さくしようというのがこのコミットの意図です。対応としてはprivateな関数の先頭に #
を付与するとMinifyされるということでそのように変更されています。
class A {
#myPrivateMethod() {}
myPublicMethod() {
this.#myPrivateMethod()
}
}
"use strict";class A{#t(){}myPublicMethod(){this.#t()}}
onOpen
イベントハンドラを使用できないように型定義を修正
Cloudflare Workers環境下ではWebSocketの
HonoのWebSocketを使用する場合に接続が開始されたイベントに onOpen
が存在しますが、Cloudflare Workers環境だけは使用することができません(ドキュメントに記載あり)。しかし、TypeScriptの型定義上は使用できる風に書けてしまうので、Cloudflare WorkersでのWebSocketは onOpen
のイベントハンドラを型定義から除外するように修正されました。
4.6.8以降の修正 その6
StreamingでResponseを返す際にETagが正常に動作するように修正
HonoにはEtagのHeaderを設定してくれるミドルウェアがあります。このミドルウェアを使用するとEtagに関するレスポンスヘッダーを設定してくれるのですが、Streamingでデータを返却する際には同じEtagを返してしまい、正常にEtagが設定されないという問題があったようです。
原因としてはStreamingを返す際にETagに設定するsha1を何で計算するかということで、StreamingのレスポンスBodyではうまく計算できなかったようです。ですのでこの修正ではレスポンスのBodyからETagに設定するsha1の計算をロジックを変更して(sreamから読み込み crypto.subtle
でsha1を計算)StreamingでもEtagが正常に設定されるという変更を行ったようです。
object
の型を削除
ハッシュ値計算関数の引数の型から曖昧な
Etagの修正と同時にハッシュ値の計算を行う関数が受け入れる引数に object
という型がありましたが、正確にはJSONデータであり、 object
という曖昧な型からJSONという正確な型に変更されました。
上記の変更で 4.6.9 がリリースされています
bunx
を用いて行うように変更
jsrのpublishに
元々はdenoのコマンドで実施していたのですが、なぜかbunxを用いてdenoを動かしています。直近v2に変更した影響ですが、理由等が書いてないので不明です。
jsrのpublishを行う時に必要なライブラリをインストールするように変更
上記の理由不明の原因はこれでしょう。どうやら 4.6.9 をリリースがうまく動作しないのは環境の問題(bunを入れて動作してみたが動作しなかったのでしょう)ではなく、そもそもリリースする deno のコマンドを打つ時に必要ライブラリをインストールする(deno install
)という手順がなくライブラリがなくてコマンドが失敗していたのを修正したようです。
cronジョブのCIから無駄な空白を削除
昨日の「4.6.8以降の修正 その5」に書きましたが、バグでないIssueを自動的に削除するcronのCIが設定されましたが、yamlファイルに無駄な空白があったようなのでそれが削除されました。
4.6.9以降の修正
deno環境下でのカバレッジを計測するように修正
Honoではいくつかのランタイムでテストが実施されていますが、denoの環境下ではカバレッジが計測されていなかったので、計測するように修正されました。
ちなみに計測自体はしていたのですが、deno環境下固有のテストについてのカバレッジが計測されてなかったので、無理やりdeno用のテストカバレッジのみを抽出して出力しているようです。
devDependencies
のパッケージをバージョンアップ
devDependencies
つまり開発のために使用しているライブラリが複数アップデートされました。特に以下のパッケージはマイナーバージョンアップを行っております。(特に zod
が古かった?)
-
@hono/node-server
(1.8.2 -> 1.13.5) -
ws
(1.17.0 -> 1.18.0) -
zod
(3.20.2 -> 3.23.8)
4.6.9以降の修正 その2
JSRからhonoをインストールした場合にTimeout Middlewareが使用できない不具合修正
JSRに公開されているHonoではTimeout Middlewareが使用出来ないようです。どうやら原因はユーザがインポートするための設定が jsr.json
に記載する必要がありますが、Timeout Middlewareの記載が漏れていたのが原因だそうです。
objectのプロパティ設定に省略記法に修正して少しでもサイズを小さくするようにリファクタリング
objectのプロパティを設定する場合は { key: key }
という風に key
というプロパティに key
という変数を設定する場合は省略記法として { key }
という風に記載するように出来ますが、これをすることでHono自体のminifyした際に少しでもサイズが小さくなるということで軽いリファクタリングがされました。
package.json
と jsr.json
の exports
に差異がないかチェックを行うように修正
Timeout Middlewareが利用出来ない件がありましたが、結局 jsr.json
自体が人の手によって管理されていることが原因ということで、それを自動的チェックしましょうというのがこのコミットの意図だと思います。ミドルウェアが追加された場合はnpm側のために package.json
の exports
が修正されますが、 jsr.json
も同時に修正する必要がありそれをビルド時にチェックするという修正がされました。
この修正により ConnInfo Helper がJSRの参照が漏れているらしく同時に修正されています。
4.6.9以降の修正 その3
Denoの環境下でディレクトリへのURLアクセスで404を返さない不具合修正
コミットの内容を見る限り、Denoだけのようですが、serve-static
を使用して静的ファイル配信を設定した場合にディレクトリへのアクセス( /public/hoge/
のような)が404にならずアプリケーションがエラーになってしまう不具合が修正されました。
Service Worker Adapterのtypoの修正
Service Worker Adapter内にあるJSDocのコメントで Service Worker
ではなく Cloudflare Workers
とtypoされているコメントが修正されました。
4.6.9以降の修正 その4
不要な判定の削除と1度しか使用しない変数の削除を行うリファクタリングを実施
タイトルからわかる通り2つの変更がこのコミットにあります。1つは「そもそもif文の判定が必要ないものの削除」という風にそもそも判定する必要がなくなったものが残っているので、それを削除したようです。
もう1つは1回しか使用しない変数定義を削除して、インラインの記述に変更するコードのリファクタリングを実施したようです。インラインにすることで可読性が失われますが、Hono自体のバンドルサイズが小さくなるということでマージされたようです。
4.6.9以降の修正 その5
判定が必要ないIF文を削除してバンドルサイズが小さくなるように修正
Honoのルーティング判定処理にて判定が必要ないIF文を削除することによりHono自体のバンドルサイズが小さくなるように修正されました。
また、IF文の修正とは別にprivateな関数名に略称が使用されており、名称がわかりにくいので略さない関数名に直すといった細かな修正も一緒に入っているようです。
4.6.9以降の修正 その6
#
を付与してバンドルサイズが小さくなるように修正
classのprivateなメンバ変数に
ここ最近Honoがprivateな関数名がMinifyされて小さくされるように #
を関数名の先頭につけていますが、classのメンバ変数名もMinifyされて小さくなるように修正されました。
ただ、ここ最近の違和感が私にはあって、そもそも現状がpublicの関数だったり、メンバ変数なんで冒頭に private
と書けばMinifyされるのでは?とか思ったりしてるので試してみる価値はあると思っています。
class Sample {
#sampleAttribute = '' // こう宣言するのではなく↓
private sampleAttribute = ''
set setAttr(val: string) {
this.sampleAttribute = val
}
get attr(): string {
return this.sampleAttribute
}
}
const sample = new Sample()
console.log(sample.sampleAttribute) // これはprivateなのでエラーになる
console.log(sample.attr) // output => ''
sample.setAttr = 'B'
console.log(sample.attr) // output => 'B'
every
を使用すると正しいURLパラメータが取得できない場合がある不具合修正
Combine Middlewareの
複数のmiddlewareを組み合わせて検証を実行するCombine Middlewareというものがあり、そのmiddlewreには every
というすべてのmiddlewareの検証が正しくないとエラーとなるAPIがあります。しかしその every
を使用するとURLパラメータが正しく取得できない場合があるという不具合がこのコミットで修正されました。
上記の変更で 4.6.10 がリリースされています
ただ、ここ最近の違和感が私にはあって、そもそも現状がpublicの関数だったり、メンバ変数なんで冒頭に private と書けばMinifyされるのでは?とか思ったりしてるので試してみる価値はあると思っています。
どうやらesbuild, 各minifierの仕様で、privateって書いてもminifyされないみたいです。
これに関しては、TypeScriptがprivate ~
をJavaScriptにするときに、publicなプロパティにしてしまうので、minifiy時にプロパティ名が圧縮されないんだと思います。
https://www.typescriptlang.org/play/?#code/MYGwhgzhAEASD2A7e0DeAoaXoAcBOAlgG5gAuAptAGYF7kAUAlGgL7otA
(授業中なので超簡易的ですが、お許しください・・・)
情報ありがとうございます!
このPRも読んだはずが、private修飾子のことまで言及されてるのが抜けてました。
TypeScript上はprivateでも結局はJavaScriptのpublicなプロパティとして残るのか。
4.6.10以降の修正
READMEに記載しているバンドルサイズの修正
4.6.9までにclass構文の関数名やメンバ変数の先頭に #
を付与することでMinifyされるようになり、Honoのバンドルサイズが13kbから12kbになったことによるREADME記載のバンドルサイズが修正されました。(実態としては11.5kbらしいです)
ビルド時の不要な型削除の進行状況カウントが1から始まるように修正
「4.6.4以降の修正 その4」で記載したようにビルド時にprivateな型の削除を行いますが、その際に表示されるログに進行状況を示す数字が出力されますが、それが0から始まるのではなく、1から始まり、全体数で終わるように修正されました。
細かいですけど #3665 はPrivate field削除のログの方ですね!
指摘ありがとうございます!
前後のコードまで見れてなかったです。
4.6.10以降の修正 その2
qs
のライブラリを追加
クエリパラメーターのベンチマークに
Honoでは他のライブラリとの比較にベンチマークを使用したりしますが、そのベンチマークの中に qs
というクエリパラメータを処理するライブラリを追加してHonoとの速度比較を行うように修正されました。
私自身 qs
というライブラリを知らなかったのですが、どうやらHonoの方が数倍処理が早いようです(ランタイムによって若干のばらつきがある)
createHandlers
で作成したハンドラーの Context
は、前段のミドルウェアで設定した Context
を考慮した型となるように修正
Honoに createHandlers
という複数のミドルウェアやハンドラーを組み合わせてルートのハンドラーを作成するというAPIがあります。このAPIを使用すると以下ようなルーティングの定義ができます。
import { createFactory } from 'hono/factory'
import { logger } from 'hono/logger'
// ...
const factory = createFactory<Env>()
const middleware = factory.createMiddleware(async (c, next) => {
c.set('foo', 'bar')
await next()
})
const handlers = factory.createHandlers(logger(), middleware, (c) => {
return c.json(c.var.foo) // this line is type error
})
app.get('/api', ...handlers)
この例では前段のミドルウェアで c.set('foo', 'bar')
があるので、後続の処理では c.var.foo
つまりは c
の Context
の型が自動的に変わっててほしいのですが、そのような型定義になっていないという問題がありました。このコミットにより createHandlers
のジェネリックの型が修正されて、前段のミドルウェア等のハンドラーの処理で返る Context
の型が後続のハンドラーに渡るようになりました。
Honoのバンドルサイズが変更前後でどのように変化するかのCIを追加
バンドルサイズを少しでも小さくした方が使用するユーザとして嬉しいのでHonoとしてはサイズを極力小さくするようにしています。そこでPull Requestやマージ後のファイルサイズがどのように変化したかを見るためのCIが作成されました。
4.6.10以降の修正 その3
Honoの修正前後による計測プログラムを整形処理の対象とするように修正
HonoにはCIで型の速度チェックやバンドルサイズのチェックを変更前と変更後に計測するプログラムがあります。そのプログラムが格納されているディレクトリも prettier
による整形の対象とするように修正されました。
4.6.10以降の修正 その4
ビルドおよび計測プログラムもLinterを行うように修正
「4.6.10以降の修正 その3」ではコードの整形を対象としましたが、ビルドおよび計測用のコードもLinterの対象とするように修正されました。
Pull Requestごとにバンドルサイズはファイル数やコード行数などの変化が修正前後で自動でコメントされるようにCIを修正
今までHonoのバンドルサイズの変化などの見るコードの変更はありましたが、Pull Requestごとにコメントとして表示される対応はされていませんでした。しかし、このコミットにより変更前後でバンドルサイズやファイル数や型数などがどのように変化するかというのがPull Requestに自動的にコメントされるように修正されました。
4.6.10以降の修正 その5
errorHandler
メソッドを #
を使用せずprivate修飾子で定義するように修正
Hono内部で使用していた
どうやら修正の意図としては #
を先頭に付与したprivateな関数名を別のところから呼び出すとうまく呼び出せずエラーになるようです。そこで #
の使用は諦めてprivate修飾子で定義するように修正されました。
上記の変更で 4.6.11 がリリースされています