Bun
Bun は Node.js や Deno とは異なる JavaScript ランタイムです。トランスコンパイラーを備えているため、TypeScript または通常の JavaScript でコードを記述できます。 Hono は Bun 上でも動作します。
1. Bun のインストール
bun コマンドをインストールするには、公式サイト の手順に従ってください。
2. セットアップ
2.1. 新しいプロジェクトのセットアップ
Bun 向けのスターターテンプレートがあります。「bun create」コマンドでプロジェクトを開始します。 この例では bun テンプレートを選択します。
bun create hono@latest my-appmy-app に移動して依存関係をインストールします。
cd my-app
bun install2.2. 既存のプロジェクトのセットアップ
既存の Bun プロジェクトでは、プロジェクトのルートディレクトリで次のコマンドを実行し、hono を依存関係に追加するだけです。
bun add hono続いて、既存の package.json に dev コマンドを追加します。
{
"scripts": {
"dev": "bun run --hot src/index.ts"
}
}最小限の設定例は Bun スターターテンプレート を参照してください。これは bun create hono@latest の実行で生成される内容です。
3. Hello World
以下が「Hello World」のスクリプトです。他のプラットフォームでの書き方とほぼ同じです。
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Bun!'))
export default app既存のプロジェクトに Hono を設定する場合、bun run dev コマンドでは「Hello World」のスクリプトを src/index.ts に配置する必要があります。
4. 実行
コマンドを実行します。
bun run dev続いて、ブラウザーで http://localhost:3000 にアクセスします。
ポート番号の変更
port をエクスポートすることで、ポート番号を指定できます。
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Bun!'))
export default app
export default {
port: 3000,
fetch: app.fetch,
} 静的ファイルの配信
静的ファイルを配信するには、@hono/bun パッケージの serveStatic を使います。
bun add @hono/bunimport { serveStatic } from '@hono/bun'
const app = new Hono()
app.use('/static/*', serveStatic({ root: './' }))
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
app.get('/', (c) => c.text('You can access: /static/hello.txt'))
app.get('*', serveStatic({ path: './static/fallback.txt' }))上記のコードは、次のディレクトリ構成で動作します。
./
├── favicon.ico
├── src
└── static
├── demo
│ └── index.html
├── fallback.txt
├── hello.txt
└── images
└── dinotocat.pngrewriteRequestPath
http://localhost:3000/static/* を ./statics に対応させるには、rewriteRequestPath オプションを使います。
app.get(
'/static/*',
serveStatic({
root: './',
rewriteRequestPath: (path) =>
path.replace(/^\/static/, '/statics'),
})
)mimes
mimes で MIME タイプを追加できます。
app.get(
'/static/*',
serveStatic({
mimes: {
m3u8: 'application/vnd.apple.mpegurl',
ts: 'video/mp2t',
},
})
)onFound
onFound で、リクエストされたファイルが見つかった場合の処理を指定できます。
app.get(
'/static/*',
serveStatic({
// ...
onFound: (_path, c) => {
c.header('Cache-Control', `public, immutable, max-age=31536000`)
},
})
)onNotFound
onNotFound で、リクエストされたファイルが見つからなかった場合の処理を指定できます。
app.get(
'/static/*',
serveStatic({
onNotFound: (path, c) => {
console.log(`${path} is not found, you access ${c.req.path}`)
},
})
)precompressed
precompressed オプションは、.br や .gz などの拡張子を持つファイルがあるかを確認し、Accept-Encoding ヘッダーに応じて配信します。Brotli、Zstd、Gzip の順に優先され、いずれもなければ元のファイルを配信します。
app.get(
'/static/*',
serveStatic({
precompressed: true,
})
)テスト
Bun 上でのテストには bun:test を使えます。
import { describe, expect, it } from 'bun:test'
import app from '.'
describe('My first test', () => {
it('Should return 200 Response', async () => {
const req = new Request('http://localhost/')
const res = await app.fetch(req)
expect(res.status).toBe(200)
})
})続いて、コマンドを実行します。
bun test index.test.ts