Skip to content

Bun ​

Bun은 또 다른 자바스크립트 런타임이다. Node.js나 Deno와는 다르다. Bun은 트랜스컴파일러를 포함하고 있어서 타입스크립트로 코드를 작성할 수 있다. Hono 또한 Bun에서 동작한다.

1. Bun 설치 ​

bun 커맨드를 설치하려면 공식 웹사이트의 안내를 따르세요.

2. 설정 ​

2.1. 새로운 프로젝트 설정하기 ​

Bun을 위한 스타터가 제공된다. "bun create" 명령어로 프로젝트를 시작한다. 이 예제에서는 bun 템플릿을 선택한다.

sh
bun create hono@latest 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

그런 다음 브라우저에서 http://localhost: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 ​

http://localhost: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('첫 번째 테스트', () => {
  it('200 응답을 반환해야 함', async () => {
    const req = new Request('http://localhost/')
    const res = await app.fetch(req)
    expect(res.status).toBe(200)
  })
})

그리고 다음 커맨드를 실행한다.

sh
bun test index.test.ts

Released under the MIT License.