Skip to content

Deno

Deno는 V8 엔진 기반의 JavaScript 런타임이다. Node.js와는 다르다.
Hono는 Deno에서도 동작한다.

Hono를 사용해 TypeScript로 코드를 작성하고, deno 커맨드로 애플리케이션을 실행하며, "Deno Deploy"에 배포할 수 있다.

1. Deno 설치

먼저 deno 커맨드를 설치한다. 자세한 내용은 공식 문서를 참고한다.

2. 설정

Deno를 위한 스타터 프로젝트를 사용할 수 있다. "create-hono" 명령어로 프로젝트를 시작한다.

sh
deno init --npm hono my-app

이 예제에서는 deno 템플릿을 선택한다.

my-app 디렉터리로 이동한다. Deno의 경우 Hono를 별도로 설치할 필요가 없다.

sh
cd my-app

3. Hello World

첫 번째 애플리케이션을 작성해 보자.

ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.text('Hello Deno!'))

Deno.serve(app.fetch)

4. 실행

단순히 이 커맨드를 실행하면 된다:

sh
deno task start

포트 번호 변경하기

main.ts 파일에서 Deno.serve의 인자를 수정해 포트 번호를 지정할 수 있다:

ts
Deno.serve(app.fetch) 
Deno.serve({ port: 8787 }, app.fetch) 

정적 파일 제공하기

정적 파일을 제공하려면 hono/middleware.ts에서 serveStatic을 가져와 사용한다.

ts
import { Hono } from 'hono'
import { serveStatic } from 'hono/deno'

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' }))

Deno.serve(app.fetch)

위 코드는 다음 디렉터리 구조에서 잘 동작한다.

./
├── favicon.ico
├── index.ts
└── static
    ├── demo
    │   └── index.html
    ├── fallback.txt
    ├── hello.txt
    └── images
        └── dinotocat.png

rewriteRequestPath

http://localhost:8000/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,
  })
)

Deno Deploy

Deno Deploy는 Deno를 위한 엣지 런타임 플랫폼이다. 이 플랫폼을 통해 전 세계 어디서나 애플리케이션을 배포할 수 있다.

Hono도 Deno Deploy를 지원한다. 자세한 내용은 공식 문서를 참고한다.

테스트

Deno에서 애플리케이션을 테스트하는 것은 간단하다. Deno.test를 사용해 테스트를 작성하고, @std/assert에서 제공하는 assertassertEquals를 활용할 수 있다.

sh
deno add jsr:@std/assert
ts
import { Hono } from 'hono'
import { assertEquals } from '@std/assert'

Deno.test('Hello World', async () => {
  const app = new Hono()
  app.get('/', (c) => c.text('Please test me'))

  const res = await app.request('http://localhost/')
  assertEquals(res.status, 200)
})

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

sh
deno test hello.ts

npm: 스펙

npm:hono도 사용할 수 있다. deno.json을 수정해서 적용한다:

json
{
  "imports": {
    "hono": "jsr:@hono/hono"
    "hono": "npm:hono"
  }
}

npm:honojsr:@hono/hono 중 하나를 선택해 사용할 수 있다.

npm:@hono/zod-validator 같은 타사 미들웨어를 타입스크립트 타입 추론과 함께 사용하려면 npm: 스펙을 사용해야 한다.

json
{
  "imports": {
    "hono": "npm:hono",
    "zod": "npm:zod",
    "@hono/zod-validator": "npm:@hono/zod-validator"
  }
}

Released under the MIT License.