コンテンツへスキップ

Bun

Bun は、もう一つのJavaScriptランタイムです。Node.jsでもDenoでもありません。Bunにはトランスコンパイラが含まれており、TypeScriptでコードを書くことができます。HonoもBunで動作します。

1. Bunのインストール

bunコマンドをインストールするには、公式ウェブサイトの手順に従ってください。

2. セットアップ

2.1. 新規プロジェクトの設定

Bun用のスターターが利用可能です。"bun create"コマンドでプロジェクトを開始します。この例ではbunテンプレートを選択します。

sh
bun create hono my-app

my-appに移動して、依存関係をインストールします。

sh
cd my-app
bun install

2.2. 既存プロジェクトの設定

既存のBunプロジェクトでは、プロジェクトルートディレクトリでhonoの依存関係をインストールするだけです。

sh
bun add hono

3. Hello World

"Hello World"スクリプトを以下に示します。他のプラットフォームで記述する場合とほぼ同じです。

ts
import { Hono } from 'hono'

const app = new Hono()
app.get('/', (c) => c.text('Hello Bun!'))

export default app

4. 実行

コマンドを実行します。

sh
bun run dev

次に、ブラウザでhttps://#:3000にアクセスします。

ポート番号の変更

portをエクスポートすることで、ポート番号を指定できます。

ts
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を使用します。

ts
import { 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.png

rewriteRequestPath

https://#:3000/static/*./staticsにマップする場合は、rewriteRequestPathオプションを使用できます。

ts
app.get(
  '/static/*',
  serveStatic({
    root: './',
    rewriteRequestPath: (path) =>
      path.replace(/^\/static/, '/statics'),
  })
)

mimes

mimesでMIMEタイプを追加できます。

ts
app.get(
  '/static/*',
  serveStatic({
    mimes: {
      m3u8: 'application/vnd.apple.mpegurl',
      ts: 'video/mp2t',
    },
  })
)

onFound

要求されたファイルが見つかった場合の処理は、onFoundで指定できます。

ts
app.get(
  '/static/*',
  serveStatic({
    // ...
    onFound: (_path, c) => {
      c.header('Cache-Control', `public, immutable, max-age=31536000`)
    },
  })
)

onNotFound

要求されたファイルが見つからない場合の処理は、onNotFoundで指定できます。

ts
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の順に優先されます。いずれも利用できない場合は、元のファイルをサービスします。

ts
app.get(
  '/static/*',
  serveStatic({
    precompressed: true,
  })
)

テスト

Bunでテストするには、bun:testを使用できます。

ts
import { describe, expect, it } from 'bun:test'
import app from '.'

describe('My first test', () => {
  it('Should return 200 Response', async () => {
    const req = new Request('https://#/')
    const res = await app.fetch(req)
    expect(res.status).toBe(200)
  })
})

次に、コマンドを実行します。

sh
bun test index.test.ts

MITライセンスの下でリリースされています。