Bun
Bun은 또 다른 자바스크립트 런타임이다. Node.js나 Deno와는 다르다. Bun은 트랜스컴파일러를 포함하고 있어서 타입스크립트로 코드를 작성할 수 있다. 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 hono3. Hello World
아래는 "Hello World" 스크립트다. 다른 플랫폼에서 작성하는 것과 거의 동일하다.
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Bun!'))
export default app4. 실행
커맨드를 실행한다.
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을 불러와 사용한다.
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.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('첫 번째 테스트', () => {
it('200 응답을 반환해야 함', async () => {
const req = new Request('http://localhost/')
const res = await app.fetch(req)
expect(res.status).toBe(200)
})
})그리고 다음 커맨드를 실행한다.
bun test index.test.ts