Bun

Bun 是另一个 JavaScript 运行时。它不是 Node.js 或 Deno。Bun 内置了 Trans Compiler,因此我们可以直接用 TypeScript 编写代码。Hono 也可以运行在 Bun 上。

1. 安装 Bun

要安装 bun 命令,请参考 官方文档 提供的说明。

2. 初始化项目

2.1. 新建项目

Bun 提供了 Starter 模板。通过 bun create 命令创建项目。本示例选择 bun 模板。

  1. bun create hono@latest my-app

进入 my-app 目录并安装依赖。

  1. cd my-app
  2. bun install

2.2. 在已有项目中使用

如果已有 Bun 项目,只需在项目根目录安装 hono 依赖即可:

  1. bun add hono

3. Hello World

“Hello World” 示例与其他平台几乎一致。

  1. import { Hono } from 'hono'
  2. const app = new Hono()
  3. app.get('/', (c) => c.text('Hello Bun!'))
  4. export default app

4. 运行

执行以下命令:

  1. bun run dev

然后在浏览器访问 http://localhost:3000

修改端口号

可以通过导出 port 来指定端口号。

  1. import { Hono } from 'hono'
  2. const app = new Hono()
  3. app.get('/', (c) => c.text('Hello Bun!'))
  4. export default {
  5. port: 3000,
  6. fetch: app.fetch,
  7. }

提供静态文件

要提供静态文件,可使用从 hono/bun 导入的 serveStatic

  1. import { serveStatic } from 'hono/bun'
  2. const app = new Hono()
  3. app.use('/static/*', serveStatic({ root: './' }))
  4. app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
  5. app.get('/', (c) => c.text('You can access: /static/hello.txt'))
  6. app.get('*', serveStatic({ path: './static/fallback.txt' }))

上述代码适配如下目录结构:

  1. ./
  2. ├── favicon.ico
  3. ├── src
  4. └── static
  5. ├── demo
  6. └── index.html
  7. ├── fallback.txt
  8. ├── hello.txt
  9. └── images
  10. └── dinotocat.png

rewriteRequestPath

如果想把 http://localhost:3000/static/* 映射到 ./statics,可以使用 rewriteRequestPath 选项:

  1. app.get(
  2. '/static/*',
  3. serveStatic({
  4. root: './',
  5. rewriteRequestPath: (path) =>
  6. path.replace(/^\/static/, '/statics'),
  7. })
  8. )

mimes

可以通过 mimes 添加 MIME 类型:

  1. app.get(
  2. '/static/*',
  3. serveStatic({
  4. mimes: {
  5. m3u8: 'application/vnd.apple.mpegurl',
  6. ts: 'video/mp2t',
  7. },
  8. })
  9. )

onFound

可使用 onFound 在文件找到时进行处理:

  1. app.get(
  2. '/static/*',
  3. serveStatic({
  4. onFound: (_path, c) => {
  5. c.header('Cache-Control', `public, immutable, max-age=31536000`)
  6. },
  7. })
  8. )

onNotFound

可使用 onNotFound 在文件未找到时进行处理:

  1. app.get(
  2. '/static/*',
  3. serveStatic({
  4. onNotFound: (path, c) => {
  5. console.log(`${path} is not found, you access ${c.req.path}`)
  6. },
  7. })
  8. )

precompressed

precompressed 选项会检查 .br.gz 等压缩文件,并根据 Accept-Encoding 优先返回 Brotli、Zstd、Gzip 压缩文件。如果都不存在,则返回原始文件。

  1. app.get(
  2. '/static/*',
  3. serveStatic({
  4. precompressed: true,
  5. })
  6. )

测试

Bun 提供 bun:test 用于测试。

  1. import { describe, expect, it } from 'bun:test'
  2. import app from '.'
  3. describe('My first test', () => {
  4. it('Should return 200 Response', async () => {
  5. const req = new Request('http://localhost/')
  6. const res = await app.fetch(req)
  7. expect(res.status).toBe(200)
  8. })
  9. })

然后运行测试命令:

  1. bun test index.test.ts